<pre class=metadata>
Title: Indexed Database API 3.0
Shortname: IndexedDB
Abstract: This document defines APIs for a database of records holding
    simple values and hierarchical objects. Each record consists of a key
    and some value. Moreover, the database maintains indexes over records
    it stores. An application developer directly uses an API to locate
    records either by their key or by using an index. A query language can
    be layered on this API. An indexed database can be implemented using a
    persistent B-tree data structure.
Status: ED
Previous Version: https://www.w3.org/TR/IndexedDB/
ED: https://w3c.github.io/IndexedDB/
TR: https://www.w3.org/TR/IndexedDB-3/
Level: 3
Editor: Ali Alabbas, Microsoft Corp. https://microsoft.com, alia@microsoft.com
Editor: Joshua Bell, Google Inc. https://google.com, jsbell@google.com
Group: webapps
Repository: w3c/IndexedDB
Test Suite: https://github.com/web-platform-tests/wpt/tree/master/IndexedDB
Favicon: logo-db.png
Complain About: accidental-2119 yes
Markup Shorthands: css no, markdown yes
</pre>

<pre class=link-defaults>
spec:html; type:dfn; for:/; text:task queue
</pre>

<pre class=anchors>
spec: html; urlPrefix: https://html.spec.whatwg.org/multipage/
    urlPrefix: dom.html
        type: interface
            text: Document; url: document
spec: ecma262; urlPrefix: https://tc39.github.io/ecma262/
    type: dfn
        url: sec-algorithm-conventions
            text: !
            text: ?
        text: abrupt completion; url: sec-completion-record-specification-type
        text: Array; url: sec-array-objects
        text: array exotic object; url: array-exotic-objects
        text: Array.prototype.sort; url: sec-array.prototype.sort
        text: ArrayBuffer; url: sec-arraybuffer-objects
        text: CreateDataProperty; url: sec-createdataproperty
        text: current Realm; url: current-realm
        text: Date; url: sec-date-objects
        text: Get; url: sec-get-o-p
        text: HasOwnProperty; url: sec-hasownproperty
        text: IdentifierName; url: prod-IdentifierName
        text: Number; url: sec-terms-and-definitions-number-type
        text: Object; url: sec-object-objects
        text: Realm; url: realm
        text: Record; url: sec-list-and-record-specification-type
        text: RegExp; url: sec-regexp-regular-expression-objects
        text: ReturnIfAbrupt; url: sec-returnifabrupt
        text: String; url: sec-terms-and-definitions-string-type
        text: ToLength; url: sec-tolength
        text: ToString; url: sec-tostring
        text: Type; url: sec-ecmascript-data-types-and-values
        text: TypeError; url: sec-native-error-types-used-in-this-standard-typeerror
        text: Uint8Array; url: sec-typedarray-objects
spec: webidl; urlPrefix: https://heycam.github.io/webidl/
    type: dfn
        text: sequence<any>; url: idl-sequence
        text: sequence<DOMString>; url: idl-sequence
</pre>

<style>
/* Default ED/WD stylesheets set "both"; not needed for logo floated right */
div.head h1 { clear: left; }

table.props {
  border-collapse: collapse;
  border-style: hidden hidden none hidden;
}
table.props thead, table.props tbody {
  border-bottom: solid;
}
table.props td, table.props th {
  border-bottom: solid thin;
  border-left: solid;
  border-right: solid;
  padding: 0.5em;
  text-align: left;
  vertical-align: top;
}

dl.domintro dt {
    font-family: Menlo, Consolas, "DejaVu Sans Mono", Monaco, monospace;

    padding-top: 0.5em;
    padding-bottom: 1em;
}
dl.domintro dt a {
    color: inherit; border-bottom-style: none;
}
dl.domintro dt code {
    font-size: inherit;
}
</style>

This is the Third Edition of Indexed Database API.
The [First Edition](https://www.w3.org/TR/2015/REC-IndexedDB-20150108/)
became a W3C Recommendation on 8 January 2015.
The [Second Edition](https://www.w3.org/TR/2018/REC-IndexedDB-2-20180130/)
became a W3C Recommendation on 30 January 2018.


<!-- ============================================================ -->
# Introduction # {#introduction}
<!-- ============================================================ -->

User agents need to store large numbers of objects locally in order to
satisfy off-line data requirements of Web applications. [[WEBSTORAGE]]
is useful for storing pairs of keys and their corresponding values.
However, it does not provide in-order retrieval of keys, efficient
searching over values, or storage of duplicate values for a key.

This specification provides a concrete API to perform advanced
key-value data management that is at the heart of most sophisticated
query processors. It does so by using transactional databases to store
keys and their corresponding values (one or more per key), and
providing a means of traversing keys in a deterministic order. This is
often implemented through the use of persistent B-tree data structures
that are considered efficient for insertion and deletion as well as
in-order traversal of very large numbers of data records.


<aside class=example id=example-open-connection>
In the following example, the API is used to access a "library"
database that holds books stored by their "isbn" attribute.
Additionally, an index is maintained on the "title" attribute of the
objects stored in the object store. This index can be used to look up
books by title, and enforces a uniqueness constraint. Another index is
maintained on the "author" attribute of the objects, and can be used
to look up books by author.

A connection to the database is opened. If the "library" database did
not already exist, it is created and an event handler creates the
object store and indexes. Finally, the opened connection is saved for
use in subsequent examples.

```js
const request = indexedDB.open("library");
let db;

request.onupgradeneeded = function() {
  // The database did not previously exist, so create object stores and indexes.
  const db = request.result;
  const store = db.createObjectStore("books", {keyPath: "isbn"});
  const titleIndex = store.createIndex("by_title", "title", {unique: true});
  const authorIndex = store.createIndex("by_author", "author");

  // Populate with initial data.
  store.put({title: "Quarry Memories", author: "Fred", isbn: 123456});
  store.put({title: "Water Buffaloes", author: "Fred", isbn: 234567});
  store.put({title: "Bedrock Nights", author: "Barney", isbn: 345678});
};

request.onsuccess = function() {
  db = request.result;
};
```

The following example populates the database using a transaction.

```js
const tx = db.transaction("books", "readwrite");
const store = tx.objectStore("books");

store.put({title: "Quarry Memories", author: "Fred", isbn: 123456});
store.put({title: "Water Buffaloes", author: "Fred", isbn: 234567});
store.put({title: "Bedrock Nights", author: "Barney", isbn: 345678});

tx.oncomplete = function() {
  // All requests have succeeded and the transaction has committed.
};
```

The following example looks up a single book in the database by title
using an index.

```js
const tx = db.transaction("books", "readonly");
const store = tx.objectStore("books");
const index = store.index("by_title");

const request = index.get("Bedrock Nights");
request.onsuccess = function() {
  const matching = request.result;
  if (matching !== undefined) {
    // A match was found.
    report(matching.isbn, matching.title, matching.author);
  } else {
    // No match was found.
    report(null);
  }
};
```

The following example looks up all books in the database by author
using an index and a cursor.

```js
const tx = db.transaction("books", "readonly");
const store = tx.objectStore("books");
const index = store.index("by_author");

const request = index.openCursor(IDBKeyRange.only("Fred"));
request.onsuccess = function() {
  const cursor = request.result;
  if (cursor) {
    // Called for each matching record.
    report(cursor.value.isbn, cursor.value.title, cursor.value.author);
    cursor.continue();
  } else {
    // No more matching records.
    report(null);
  }
};
```

The following example shows how errors could be handled when a request
fails.

```js
const tx = db.transaction("books", "readwrite");
const store = tx.objectStore("books");
const request = store.put({title: "Water Buffaloes", author: "Slate", isbn: 987654});
request.onerror = function(event) {
  // The uniqueness constraint of the "by_title" index failed.
  report(request.error);
  // Could call event.preventDefault() to prevent the transaction from aborting.
};
tx.onabort = function() {
  // Otherwise the transaction will automatically abort due the failed request.
  report(tx.error);
};
```

The database connection can be closed when it is no longer needed.

```js
db.close();
```

In the future, the database might have grown to contain other object
stores and indexes. The following example shows one way to handle
migrating from an older version of the database.

```js
const request = indexedDB.open("library", 3); // Request version 3.
let db;

request.onupgradeneeded = function(event) {
  const db = request.result;
  if (event.oldVersion < 1) {
    // Version 1 is the first version of the database.
    const store = db.createObjectStore("books", {keyPath: "isbn"});
    const titleIndex = store.createIndex("by_title", "title", {unique: true});
    const authorIndex = store.createIndex("by_author", "author");
  }
  if (event.oldVersion < 2) {
    // Version 2 introduces a new index of books by year.
    const bookStore = request.transaction.objectStore("books");
    const yearIndex = bookStore.createIndex("by_year", "year");
  }
  if (event.oldVersion < 3) {
    // Version 3 introduces a new object store for magazines with two indexes.
    const magazines = db.createObjectStore("magazines");
    const publisherIndex = magazines.createIndex("by_publisher", "publisher");
    const frequencyIndex = magazines.createIndex("by_frequency", "frequency");
  }
};

request.onsuccess = function() {
  db = request.result; // db.version will be 3.
};
```
</aside>

<aside class=example id=handling-versionchange>
A single database can be used by multiple clients (pages and workers)
simultaneously &mdash; transactions ensure they don't clash while reading and writing.
If a new client wants to upgrade the database (via the <a event>`upgradeneeded`</a>
event), it cannot do so until all other clients close their connection to the
current version of the database.

To avoid blocking a new client from upgrading, clients can listen for the
<a event>`versionchange`</a> event. This fires when another client is wanting to upgrade the
database. To allow this to continue, react to the <a event>`versionchange`</a> event by doing
something that ultimately closes this client's [=/connection=] to the database.

One way of doing this is to reload the page:

```js
db.onversionchange = function() {
  // First, save any unsaved data:
  saveUnsavedData().then(function() {
    // If the document isn't being actively used, it could be appropriate to reload
    // the page without the user's interaction.
    if (!document.hasFocus()) {
      location.reload();
      // Reloading will close the database, and also reload with the new JavaScript
      // and database definitions.
    } else {
      // If the document has focus, it can be too disruptive to reload the page.
      // Maybe ask the user to do it manually:
      displayMessage("Please reload this page for the latest version.");
    }
  });
};

function saveUnsavedData() {
  // How you do this depends on your app.
}

function displayMessage() {
  // Show a non-modal message to the user.
}
```

Another way is to call the [=/connection=]'s {{IDBDatabase/close()}} method. However, you need to make
sure your app is aware of this, as subsequent attempts to access the database
will fail.

```js
db.onversionchange = function() {
  saveUnsavedData().then(function() {
    db.close();
    stopUsingTheDatabase();
  });
};

function stopUsingTheDatabase() {
  // Put the app into a state where it no longer uses the database.
}
```

The new client (the one attempting the upgrade) can use the <a event>`blocked`</a> event to
detect if other clients are preventing the upgrade from happening. The <a event>`blocked`</a>
event fires if other clients still hold a connection to the database after their
<a event>`versionchange`</a> events have fired.

```js
const request = indexedDB.open("library", 4); // Request version 4.
let blockedTimeout;

request.onblocked = function() {
  // Give the other clients time to save data asynchronously.
  blockedTimeout = setTimeout(function() {
    displayMessage("Upgrade blocked - Please close other tabs displaying this site.");
  }, 1000);
};

request.onupgradeneeded = function(event) {
  clearTimeout(blockedTimeout);
  hideMessage();
  // ...
};

function hideMessage() {
  // Hide a previously displayed message.
}
```

The user will only see the above message if another client fails to disconnect
from the database. Ideally the user will never see this.
</aside>

<!-- ============================================================ -->
# Constructs # {#constructs}
<!-- ============================================================ -->

A <dfn>name</dfn> is a [=string=] equivalent to a {{DOMString}};
that is, an arbitrary sequence of 16-bit code units of any length,
including the empty string. [=/Names=] are always compared as
opaque sequences of 16-bit code units.

<aside class=note>
  As a result, [=/name=] comparison is sensitive to variations in case
  as well as other minor variations such as normalization form, the
  inclusion or omission of controls, and other variations in Unicode
  text. [[Charmod-Norm]]

  If an implementation uses a storage mechanism which does not support
  arbitrary strings, the implementation can use an escaping mechanism
  or something similar to map the provided name to a string that it
  can store.
</aside>

A <dfn>sorted name list</dfn> is a list containing [=/names=]
sorted in ascending order by 16-bit code unit.

<details class=note>
    <summary>Details</summary>
    This matches the [=Array.prototype.sort=] on an [=Array=] of
    [=Strings=]. This ordering compares the 16-bit code units in each
    string, producing a highly efficient, consistent, and deterministic
    sort order. The resulting list will not match any particular
    alphabet or lexicographical order, particularly for code points
    represented by a surrogate pair.
</details>


<!-- ============================================================ -->
## Database ## {#database-construct}
<!-- ============================================================ -->

Each [=/origin=] has an associated set of [=databases=]. A
<dfn>database</dfn> has zero or more [=/object stores=] which
hold the data stored in the database.

<div dfn-for=database>

A [=database=] has a <dfn>name</dfn> which identifies it within a
specific [=/origin=]. The name is a [=/name=],
and stays constant for the lifetime of the database.

A [=database=] has a <dfn>version</dfn>. When a database is first
created, its [=database/version=] is 0 (zero).

<aside class=note>
  Each [=database=] has one version at a time; a [=database=] can't
  exist in multiple versions at once. The only way to change the
  version is using an [=/upgrade transaction=].
</aside>

A [=database=] has at most one associated <dfn>upgrade transaction</dfn>,
which is either null or an [=/upgrade transaction=], and is initially null.

</div>

<!-- ============================================================ -->
### Database Connection ### {#database-connection}
<!-- ============================================================ -->

Script does not interact with [=databases=] directly. Instead,
script has indirect access via a <dfn lt="connection|connected">connection</dfn>.
A [=/connection=] object can be used to manipulate the objects of
that [=database=]. It is also the only way to obtain a
[=/transaction=] for that [=database=].

The act of opening a [=database=] creates a [=/connection=].
There may be multiple [=/connections=] to a given [=database=] at
any given time.

A [=/connection=] can only access [=databases=] associated with the
[=/origin=] of the global scope from which the [=/connection=] is
opened.

<aside class=note>
  This is not affected by changes to the {{Document}}'s
  {{Document/domain}}.
</aside>

<div dfn-for=connection>

A [=/connection=] has a <dfn>version</dfn>, which is set when
the [=/connection=] is created. It remains constant for the
lifetime of the [=/connection=] unless an <a data-lt="abort
an upgrade transaction">upgrade is aborted</a>, in which
case it is set to the previous version of the [=database=]. Once
the [=/connection=] is closed the
[=connection/version=] does not change.

Each connection has a <dfn>close pending flag</dfn> which is initially
false.

When a [=/connection=] is initially created it is in an opened
state. The connection can be <dfn>closed</dfn> through several means.
If the execution context where the [=/connection=] was created is
destroyed (for example due to the user navigating away from that
page), the connection is closed. The connection can also be closed
explicitly using the steps to [=close a database connection=]. When
the connection is closed its [=connection/close pending flag=] is always set to true if
it hasn't already been.

A [=/connection=] may be closed by a user agent in exceptional
circumstances, for example due to loss of access to the file system, a
permission change, or clearing of the origin's storage. If this occurs
the user agent must run [=close a database
connection=] with the [=/connection=] and with the |forced flag| set to true.

A [=/connection=] has an <dfn>object store set</dfn>, which is
initialized to the set of [=/object stores=] in the associated
[=database=] when the [=/connection=] is created. The contents of the
set will remain constant except when an [=/upgrade transaction=] is
running.

A [=/connection=]'s [=get the parent=] algorithm returns
null.

A <dfn event>`versionchange`</dfn> will be fired at an open
[=/connection=] if an attempt is made to upgrade or delete the
[=database=]. This gives the [=/connection=] the opportunity to close
to allow the upgrade or delete to proceed.

</div>


<!-- ============================================================ -->
## Object Store ## {#object-store-construct}
<!-- ============================================================ -->

An <dfn>object store</dfn> is the primary storage mechanism for
storing data in a [=database=].

<div dfn-for=object-store>

Each database has a set of [=/object stores=]. The set of [=/object
stores=] can be changed, but only using an [=/upgrade transaction=],
i.e. in response to an <a event>`upgradeneeded`</a> event. When a
new database is created it doesn't contain any [=/object stores=].

An [=/object store=] has a <dfn>list of records</dfn> which hold the
data stored in the object store. Each <dfn>record</dfn> consists of a
[=/key=] and a [=/value=]. The list is sorted according to key in
[=ascending=] order. There can never be multiple records in a given object
store with the same key.

An [=/object store=] has a <dfn>name</dfn>, which is a [=/name=].
At any one time, the name is unique
within the [=database=] to which it belongs.

An [=/object store=] optionally has a <dfn>key path</dfn>. If the
object store has a key path it is said to use <dfn>in-line keys</dfn>.
Otherwise it is said to use <dfn>out-of-line keys</dfn>.

An [=/object store=] optionally has a [=key generator=].

An object store can derive a [=/key=] for a [=object-store/record=] from
one of three sources:

1. A [=key generator=]. A key generator generates a monotonically
    increasing numbers every time a key is needed.

1. Keys can be derived via a [=object-store/key path=].

1. Keys can also be explicitly specified when a [=/value=] is stored
    in the object store.

</div>

<!-- ============================================================ -->
### Object Store Handle ### {#object-store-handle-construct}
<!-- ============================================================ -->

Script does not interact with [=/object stores=] directly. Instead,
within a [=/transaction=], script has indirect access via an
<dfn>object store handle</dfn>.

<div dfn-for=object-store-handle>

An [=/object store handle=] has an associated <dfn>object store</dfn>
and an associated <dfn>transaction</dfn>. Multiple handles may be
associated with the same [=/object store=] in different
[=/transactions=], but there must be only one [=/object store handle=]
associated with a particular [=/object store=] within a
[=/transaction=].

An [=/object store handle=] has an <dfn>index set</dfn>, which is
initialized to the set of [=/indexes=] that reference the associated
[=object-store-handle/object store=] when the [=/object store handle=]
is created. The contents of the set will remain constant except when
an [=/upgrade transaction=] is running.

An [=/object store handle=] has a <dfn>name</dfn>, which is
initialized to the [=object-store/name=] of the associated
[=object-store-handle/object store=] when the [=/object store handle=]
is created. The name will remain constant except when an [=/upgrade
transaction=] is running.

</div>

<!-- ============================================================ -->
## Values ## {#value-construct}
<!-- ============================================================ -->

Each record is associated with a <dfn>value</dfn>. User agents must
support any [=serializable object=]. This includes simple types
such as [=String=] primitive values and [=Date=] objects as well as
[=Object=] and [=Array=] instances, {{File}} objects, {{Blob}}
objects, {{ImageData}} objects, and so on. Record [=/values=] are
stored and retrieved by value rather than by reference; later changes
to a value have no effect on the record stored in the database.

Record [=/values=] are [=/Records=] output by the
<a abstract-op>StructuredSerializeForStorage</a> operation.


<!-- ============================================================ -->
## Keys ## {#key-construct}
<!-- ============================================================ -->

In order to efficiently retrieve [=object-store/records=] stored in an indexed
database, each [=object-store/record=] is organized according to its
<dfn>key</dfn>.

<div dfn-for=key>

A [=/key=] has an associated <dfn>type</dfn> which is one of:
*number*,
*date*,
*string*,
*binary*,
or
*array*.

A [=/key=] also has an associated <dfn>value</dfn>, which will
be either:
an {{unrestricted double}} if type is *number* or *date*,
a {{DOMString}} if type is *string*,
a [=byte sequence=] if type is *binary*,
or a [=/list=] of other [=/keys=] if type is *array*.

</div>

An ECMAScript [[!ECMA-262]] value can be converted to a [=/key=] by
following the steps to [=convert a value to a key=].

<aside class=note>
  The following ECMAScript types are valid keys:

  * [=Number=] primitive values, except NaN. This includes Infinity
      and -Infinity.
  * [=Date=] objects, except where the \[[DateValue]]
      internal slot is NaN.
  * [=String=] primitive values.
  * [=ArrayBuffer=] objects (or views on buffers such as
      [=Uint8Array=]).
  * [=Array=] objects, where every item is defined, is itself a valid
      key, and does not directly or indirectly contain itself. This
      includes empty arrays. Arrays can contain other arrays.

  Attempting to convert other ECMAScript values to a [=/key=]
  will fail.
</aside>

An <dfn>array key</dfn> is a [=/key=] with [=key/type=] *array*.
The <dfn>subkeys</dfn> of an [=array key=] are the [=list/items=] of the
[=array key=]'s [=key/value=].

<div class=algorithm>

To <dfn>compare two keys</dfn> |a| and |b|, run these steps:

1. Let |ta| be the [=key/type=] of |a|.

1. Let |tb| be the [=key/type=] of |b|.

1. If |ta| does not equal |tb|, then run these steps:

    1. If |ta| is *array*, then return 1.
    1. If |tb| is *array*, then return -1.
    1. If |ta| is *binary*, then return 1.
    1. If |tb| is *binary*, then return -1.
    1. If |ta| is *string*, then return 1.
    1. If |tb| is *string*, then return -1.
    1. If |ta| is *date*, then return 1.
    1. [=/Assert=]: |tb| is *date*.
    1. Return -1.

1. Let |va| be the [=key/value=] of |a|.

1. Let |vb| be the [=key/value=] of |b|.

1. Switch on |ta|:

    <dl class=switch>
      : *number*
      : *date*
      ::
          1. If |va| is greater than |vb|, then return 1.
          1. If |va| is less than |vb|, then return -1.
          1. Return 0.

      : *string*
      ::
          1. If |va| is [=code unit less than=] |vb|, then return -1.
          1. If |vb| is [=code unit less than=] |va|, then return 1.
          1. Return 0.

      : *binary*
      ::
          1. If |va| is [=byte less than=] |vb|, then return -1.
          1. If |vb| is [=byte less than=] |va|, then return 1.
          1. Return 0.

      : *array*
      ::
          1. Let |length| be the lesser of |va|'s [=list/size=] and |vb|'s [=list/size=].
          1. Let |i| be 0.
          1. While |i| is less than |length|, then:

              1. Let |c| be the result of recursively running [=compare two keys=] with |va|[|i|] and |vb|[|i|].
              1. If |c| is not 0, return |c|.
              1. Increase |i| by 1.

          1. If |va|'s [=list/size=] is greater than |vb|'s [=list/size=], then return 1.
          1. If |va|'s [=list/size=] is less than |vb|'s [=list/size=], then return -1.
          1. Return 0.

    </dl>

</div>

The [=/key=] |a| is <dfn lt="greater than|ascending">greater than</dfn> the [=/key=] |b| if the
result of running [=compare two keys=] with |a| and |b|
is 1.

The [=/key=] |a| is <dfn>less than</dfn> the [=/key=] |b| if the
result of running [=compare two keys=] with |a| and |b|
is -1.

The [=/key=] |a| is <dfn>equal to</dfn> the [=/key=] |b| if the result
of running [=compare two keys=] with |a| and |b| is 0.

<aside class=note>
  As a result of the above rules, negative infinity is the lowest
  possible value for a [=/key=].
  *Number* keys are less than *date* keys.
  *Date* keys are less than *string* keys.
  *String* keys are less than *binary* keys.
  *Binary* keys are less than *array* keys.
  There is no highest possible [=/key=] value.
  This is because an array of any candidate highest [=/key=]
  followed by another [=/key=] is even higher.
</aside>

<aside class=note>
  Members of *binary* keys are compared as unsigned [=byte=] values
  (in the range 0 to 255 inclusive) rather than signed {{byte}} values (in the range
  -128 to 127 inclusive).
</aside>


<!-- ============================================================ -->
## Key Path ## {#key-path-construct}
<!-- ============================================================ -->

A <dfn>key path</dfn> is a string or list of strings
that defines how to extract a [=/key=]
from a [=/value=]. A <dfn>valid key path</dfn> is one of:

* An empty string.
* An <dfn>identifier</dfn>, which is a string matching the
    [=IdentifierName=] production from the ECMAScript Language
    Specification [[!ECMA-262]].
* A string consisting of two or more [=identifiers=] separated
    by periods (U+002E FULL STOP).
* A non-empty list containing only strings
    conforming to the above requirements.

<aside class=note>
  Spaces are not allowed within a key path.
</aside>

[=/Key path=] values can only be accessed from properties explicitly
copied by <a abstract-op>StructuredSerializeForStorage</a>, as well as the
following type-specific properties:

<table class=props>
  <tr><th>Type</th><th>Properties</th></tr>
  <tr><td>{{Blob}}</td><td>{{Blob/size}}, {{Blob/type}}</td></tr>
  <tr><td>{{File}}</td><td>{{File/name}}, {{File/lastModified}}</td></tr>
  <tr><td>[=Array=]</td><td>`length`</td></tr>
  <tr><td>[=String=]</td><td>`length`</td></tr>
</table>


<!-- ============================================================ -->
## Index ## {#index-construct}
<!-- ============================================================ -->

It is sometimes useful to retrieve [=object-store/records=] in an
[=/object store=] through other means than their
[=/key=]. An <dfn id=index-concept>index</dfn> allows looking up
[=object-store/records=] in an [=/object store=] using properties of the
[=/values=] in the [=/object stores=] [=object-store/records=].

<div dfn-for=index>

An index is a specialized persistent key-value storage and has a <dfn
lt="referenced|references">referenced</dfn> [=/object store=]. The
index has a <dfn>list of records</dfn> which hold the data stored in
the index. The <dfn>records</dfn> in an index are automatically populated
whenever records in the [=referenced=] object store are inserted,
updated or deleted. There can be several [=/indexes=] referencing the
same [=/object store=], in which changes to the object store cause all
such indexes to get updated.

The <dfn>values</dfn> in the index's [=index/records=] are always values of [=/keys=]
in the index's [=referenced=] object store. The <dfn>keys</dfn> are derived from
the referenced object store's [=/values=] using a <dfn>key path</dfn>.
If a given [=object-store/record=] with key |X| in the object store referenced by
the index has the value |A|, and <a data-lt="extract a key from a
value using a key path">evaluating</a> the index's [=index/key path=]
on |A| yields the result |Y|, then the index will contain a record
with key |Y| and value |X|.

<aside class=example id=example-index-entries>
  For example, if an index's [=referenced=] object store contains a
  record with the key `123` and the value `{ name:
  "Alice", title: "CEO" }`, and the index's [=index/key path=]
  is "`name`" then the index would contain a record with
  the key "`Alice`" and the value `123`.
</aside>

Records in an index are said to have a <dfn>referenced value</dfn>.
This is the value of the record in the index's referenced object store
which has a key equal to the index's record's value. So in the example
above, the record in the index whose [=index/key=] is |Y| and value is |X| has a
[=referenced value=] of |A|.

<aside class=example id=example-index-referenced-values>
  In the preceding example, the record in the index with key
  "`Alice`" and value `123` would have a
  [=referenced value=] of `{ name: "Alice", title: "CEO"
  }`.
</aside>

<aside class=note>
  Each record in an index references one and only one record in the
  index's [=referenced=] object store. However there can be multiple
  records in an index which reference the same record in the object
  store. And there can also be no records in an index which reference
  a given record in an object store.
</aside>

The [=object-store/records=] in an index are always sorted according to the
[=object-store/record=]'s key. However unlike object stores, a given index can
contain multiple records with the same key. Such records are
additionally sorted according to the [=/index=]'s [=object-store/record=]'s value
(meaning the key of the record in the referenced [=/object store=]).

An [=/index=] has a <dfn>name</dfn>, which is a [=/name=].
At any one time, the name is
unique within index's [=referenced=] [=/object store=].

An [=/index=] has a <dfn>unique flag</dfn>. When
true, the index enforces that no two [=object-store/records=] in the index has
the same key. If a [=object-store/record=] in the index's referenced object
store is attempted to be inserted or modified such that evaluating the
index's key path on the records new value yields a result which
already exists in the index, then the attempted modification to the
object store fails.

An [=/index=] has a <dfn>multiEntry flag</dfn>. This flag affects how
the index behaves when the result of evaluating the index's
[=index/key path=] yields an [=array key=]. If its [=index/multiEntry flag=]
is false, then a single [=object-store/record=] whose [=/key=] is an [=array key=]
is added to the index. If its [=index/multiEntry flag=] is true, then
one [=object-store/record=] is added to the index for each of the [=subkeys=].

</div>

<!-- ============================================================ -->
### Index Handle ### {#index-handle-construct}
<!-- ============================================================ -->

Script does not interact with [=/indexes=] directly. Instead, within
a [=/transaction=], script has indirect access via an <dfn>index
handle</dfn>.

<div dfn-for=index-handle>

An [=index handle=] has an associated <dfn>index</dfn> and an
associated <dfn>object store handle</dfn>. The <dfn>transaction</dfn>
of an [=index handle=] is the [=object-store-handle/transaction=] of
its associated [=/object store handle=]. Multiple handles may be
associated with the same [=/index=] in different [=/transactions=],
but there must be only one [=index handle=] associated with a
particular [=/index=] within a [=/transaction=].

An [=index handle=] has a <dfn>name</dfn>, which is initialized to the
[=index/name=] of the associated [=index-handle/index=] when the
[=index handle=] is created. The name will remain constant except when
an [=/upgrade transaction=] is running.

</div>

<!-- ============================================================ -->
## Transactions ## {#transaction-construct}
<!-- ============================================================ -->

A <dfn id=transaction-concept>Transaction</dfn> is used to interact
with the data in a [=database=]. Whenever data is read or written
to the database it is done by using a [=/transaction=].

<div dfn-for=transaction>

[=/Transactions=] offer some protection from application and system
failures. A [=/transaction=] may be used to store multiple data
records or to conditionally modify certain data records. A
[=/transaction=] represents an atomic and durable set of data access
and data mutation operations.

All transactions are created through a [=/connection=], which is the
transaction's <dfn>connection</dfn>.

A [=/transaction=] has a <dfn>scope</dfn> that determines the
[=/object stores=] with which the transaction may interact. A
transaction's scope remains fixed for the lifetime of that
transaction.

A [=/transaction=] has a <dfn>mode</dfn> that determines which types
of interactions can be performed upon that transaction. The [=transaction/mode=]
is set when the transaction is created and remains fixed for the life
of the transaction. A [=/transaction=]'s [=transaction/mode=] is one of the
following:

: {{"readonly"}}
::
    The transaction is only allowed to read data. No modifications can
    be done by this type of transaction. This has the advantage that
    several [=read-only transactions=] can run at the same time even
    if their [=transaction/scopes=] are overlapping, i.e. if they are using the
    same object stores. This type of transaction can be created any
    time once a database has been opened.

: {{"readwrite"}}
::
    The transaction is allowed to read, modify and delete data from
    existing object stores. However object stores and indexes can't be
    added or removed. Multiple {{"readwrite"}} transactions
    can't run at the same time if their [=transaction/scopes=] are overlapping
    since that would mean that they can modify each other's data in
    the middle of the transaction. This type of transaction can be
    created any time once a database has been opened.

: {{"versionchange"}}
::
    The transaction is allowed to read, modify and delete data from
    existing object stores, and can also create and remove object
    stores and indexes. It is the only type of transaction that can do
    so. This type of transaction can't be manually created, but
    instead is created automatically when an
    <a event>`upgradeneeded`</a> event is fired.

A [=/transaction=] optionally has a <dfn>cleanup event loop</dfn>
which is an [=event loop=].

A [=/transaction=] has a <dfn>request list</dfn> of pending [=/requests=]
which have been made against the transaction.

A [=/transaction=] has a <dfn>error</dfn> which is set if the
[=/transaction=] is [=transaction/aborted=].

A [=/transaction=]'s [=get the parent=] algorithm returns the
transaction's [=transaction/connection=].

A <dfn>read-only transaction</dfn> is
a [=/transaction=] with [=transaction/mode=] {{"readonly"}}.

A <dfn>read/write transaction</dfn>
is a [=/transaction=] with [=transaction/mode=] {{"readwrite"}}.

<!-- ============================================================ -->
### Transaction Lifecycle ### {#transaction-lifecycle}
<!-- ============================================================ -->

A [=/transaction=] has a <dfn>state</dfn>, which is one
of the following:

: <dfn>active</dfn>
::
    A transaction is in this state when it is first [=transaction/created=],
    and during dispatch of an event from a [=/request=] associated with the transaction.

    New [=/requests=] can be made against the transaction when it is in this state.

: <dfn>inactive</dfn>
::
    A transaction is in this state after control returns to the event
    loop after its creation, and when events are not being dispatched.

    No [=/requests=] can be made against the transaction when it is in this state.

: <dfn>committing</dfn>
::
    Once all [=/requests=] associated with a transaction have completed,
    the transaction will enter this state as it attempts to [=commit=].

    No [=/requests=] can be made against the transaction when it is in this state.

: <dfn>finished</dfn>
::
    Once a transaction has committed or aborted, it enters this state.

    No [=/requests=] can be made against the transaction when it is in this state.

Transactions are expected to be short lived. This is encouraged by the
[=transaction/commit|automatic committing=] functionality
described below.

<aside class=note>
  Authors can still cause transactions to run for a long time;
  however, this usage pattern is not advised as it can lead to a poor
  user experience.
</aside>

The <dfn>lifetime</dfn> of a
[=/transaction=] is as follows:

1. A transaction is <dfn>created</dfn> with a [=transaction/scope=] and a
    [=transaction/mode=]. When a transaction is created its
    [=transaction/state=] is initially [=transaction/active=].

1. When an implementation is able to enforce the constraints for the
    transaction's [=transaction/scope=] and [=transaction/mode=],
    defined [below](#transaction-scheduling), the implementation must
    [=queue a task=] to <dfn lt="start|started">start</dfn> the
    transaction asynchronously.

    Once the transaction has been [=transaction/started=] the
    implementation can begin executing the [=/requests=] placed
    against the transaction. Requests must be executed in the order in
    which they were made against the transaction. Likewise, their
    results must be returned in the order the requests were placed
    against a specific transaction. There is no guarantee about the
    order that results from requests in different transactions are
    returned.

    <aside class=note>
        Transaction [=transaction/modes=] ensure that two
        requests placed against different transactions can execute in any
        order without affecting what resulting data is stored in the
        database.
    </aside>

1. When each [=/request=] associated with a transaction is [=request/processed=],
    a <a event>`success`</a> or <a event>`error`</a> [=event=] will be
    fired. While the event is being [=dispatched=], the transaction
    [=transaction/state=] is set to [=transaction/active=], allowing
    additional requests to be made against the transaction. Once the
    event dispatch is complete, the transaction's
    [=transaction/state=] is set to [=transaction/inactive=] again.

1. A transaction can be <dfn lt="abort|aborting|aborted">aborted</dfn>
    at any time before it is [=transaction/finished=], even if the
    transaction isn't currently [=transaction/active=] or hasn't yet
    [=transaction/started=].

    An explicit call to {{IDBTransaction/abort()}} will initiate an
    [=transaction/abort=]. An abort will also be initiated following a
    failed request that is not handled by script.

    When a transaction is aborted the implementation must undo (roll
    back) any changes that were made to the [=database=] during that
    transaction. This includes both changes to the contents of
    [=/object stores=] as well as additions and removals of [=/object
    stores=] and [=/indexes=].

1. The implementation must attempt to <dfn lt="commit|committed">commit</dfn>
    a transaction when all [=/requests=] placed against the
    transaction have completed and their returned results handled, no
    new requests have been placed against the transaction, and the
    transaction has not been [=transaction/aborted=]

    An explicit call to {{IDBTransaction/commit()}} will initiate a
    [=transaction/commit=] without waiting for request results to be
    handled by script.

    When committing, the transaction [=transaction/state=] is set to
    [=transaction/committing=]. The implementation must atomically
    write any changes to the [=database=] made by requests placed
    against the transaction. That is, either all of the changes must
    be written, or if an error occurs, such as a disk write error, the
    implementation must not write any of the changes to the database,
    and the steps to [=abort a transaction=] will be followed.

1. When a transaction is [=transaction/committed=] or [=transaction/aborted=],
    its [=transaction/state=] is set to [=transaction/finished=].


The implementation must allow [=/requests=] to be [=request/placed=]
against the transaction whenever it is [=transaction/active=]. This is
the case even if the transaction has not yet been
[=transaction/started=]. Until the transaction is
[=transaction/started=] the implementation must not execute these
requests; however, the implementation must keep track of the
[=/requests=] and their order.

To <dfn id=cleanup-indexed-database-transactions export>cleanup Indexed Database transactions</dfn>, run the following steps.
They will return true if any transactions were cleaned up, or false otherwise.

<div class=algorithm>
    1. If there are no [=/transactions=] with [=transaction/cleanup
        event loop=] matching the current [=event loop=], return false.

    1. For each [=/transaction=] |transaction| with [=transaction/cleanup event loop=]
        matching the current [=event loop=]:

        1. Set |transaction|'s [=transaction/state=] to [=transaction/inactive=].

        1. Clear |transaction|'s [=transaction/cleanup event loop=].

    1. Return true.
</div>

<aside class=note>
  This behavior is invoked by [[HTML]]. It ensures that
  [=/transactions=] created by a script call
  to {{IDBDatabase/transaction()}} are deactivated once the task that
  invoked the script has completed. The steps are run at most once for
  each [=/transaction=].
</aside>

<!-- ============================================================ -->
### Transaction Scheduling ### {#transaction-scheduling}
<!-- ============================================================ -->

An event with type <dfn event>`complete`</dfn> is fired at
a [=/transaction=] that has successfully [=transaction/committed=].

An event with type <dfn event>`abort`</dfn> is fired at
a [=/transaction=] that has [=transaction/aborted=].

The following constraints define when a [=/transaction=] can be
[=transaction/started=]:

* Any number of [=read-only transactions=] are allowed to run
    concurrently, even if the transaction's [=transaction/scope=] overlap and
    include the same [=/object stores=]. As long as a [=read-only
    transaction=] is running, the data that the implementation returns
    through [=/requests=] created with that transaction must remain
    constant. That is, two requests to read the same piece of data
    must yield the same result both for the case when data is found
    and the result is that data, and for the case when data is not
    found and a lack of data is indicated.

    <aside class=note>
      There are a number of ways that an implementation can ensure
      this. The implementation could prevent any <a>read/write
      transaction</a>, whose scope overlaps the scope of the
      [=read-only transaction=], from starting until the
      [=read-only transaction=] finishes. Or the implementation
      could allow the [=read-only transaction=] to see a snapshot
      of the contents of the [=/object stores=] which is taken when
      the [=read-only transaction=] started.
    </aside>

* Similarly, implementations must ensure that a <a>read/write
    transaction</a> is only affected by changes to [=/object
    stores=] that are made using the transaction itself. For
    example, the implementation must ensure that another transaction
    does not modify the contents of [=/object stores=] in the
    <a>read/write transaction</a>'s [=transaction/scope=]. The implementation
    must also ensure that if the <a>read/write transaction</a>
    completes successfully, the changes written to [=/object
    stores=] using the transaction can be committed to the
    [=database=] without merge conflicts. An implementation must
    not abort a transaction due to merge conflicts.

* If multiple <a>read/write transactions</a> are attempting to access
    the same object store (i.e. if they have overlapping [=transaction/scope=]),
    the transaction that was [=transaction/created=] first must be the transaction
    which gets access to the object store first. Due to the
    requirements in the previous paragraph, this also means that it is
    the only transaction which has access to the object store until
    the transaction is [=transaction/finished=].

* Any transaction [=transaction/created=] after a <a>read/write transaction</a>
    must see the changes written by the <a>read/write transaction</a>.
    So if a <a>read/write transaction</a>, A, is created, and later
    another transaction B, is created, and the two transactions have
    overlapping [=transaction/scopes=], then B must see any changes made to any
    [=/object stores=] that are part of that overlapping [=transaction/scope=].
    Due to the requirements in the previous paragraph, this also means
    that the B transaction does not have access to any [=/object
    stores=] in that overlapping [=transaction/scope=] until the A transaction is
    [=transaction/finished=].

    <aside class=note>
      Generally speaking, the above requirements mean that any
      transaction which has an overlapping scope with a <a>read/write
      transaction</a> and which was created after that <a>read/write
      transaction</a>, can't run in parallel with that <a>read/write
      transaction</a>.
    </aside>

* User agents must ensure a reasonable level of fairness across
    transactions to prevent starvation. For example, if multiple
    [=read-only transactions=] are started one after another the
    implementation must not indefinitely prevent a pending
    <a>read/write transaction</a> from [=transaction/starting=].

</div>


<!-- ============================================================ -->
### Upgrade Transactions ### {#upgrade-transaction-construct}
<!-- ============================================================ -->

An <dfn>upgrade transaction</dfn> is a [=/transaction=] with [=transaction/mode=]
{{"versionchange"}}.

An [=/upgrade transaction=] is automatically created when running the
steps to [=run an upgrade transaction=] after a [=/connection=]
is opened to a [=/database=], if a [=database/version=] greater than
the current [=database/version=] is specified. This [=/transaction=]
will be active inside the <a event>`upgradeneeded`</a> event
handler.

<aside class=note>
  An [=/upgrade transaction=] enables the creation, renaming, and
  deletion of [=/object stores=] and [=/indexes=] in a [=/database=].

  An [=/upgrade transaction=] is exclusive. The steps to [=open a
  database=] ensure that only one [=/connection=] to the database is
  open when an [=/upgrade transaction=] is running.
  The <a event>`upgradeneeded`</a> event isn't fired, and thus the
  [=/upgrade transaction=] isn't started, until all other
  [=/connections=] to the same [=/database=] are closed. This ensures
  that all previous transactions are [=transaction/finished=]. As long
  as an [=/upgrade transaction=] is running, attempts to open more
  [=/connections=] to the same [=/database=] are delayed, and any
  attempts to use the same [=/connection=] to start additional
  transactions by calling {{IDBDatabase/transaction()}} will throw an
  exception. Thus [=/upgrade transactions=] not only ensure that no
  other transactions are running concurrently, but also ensure that no
  new transactions are queued against the same [=/database=] as long
  as the transaction is running.

  This ensures that once an [=/upgrade transaction=] is complete, the
  set of [=/object stores=] and [=/indexes=] in a [=/database=] remain
  constant for the lifetime of all subsequent [=/connections=] and
  [=/transactions=].
</aside>


<!-- ============================================================ -->
## Requests ## {#request-construct}
<!-- ============================================================ -->

Each asynchronous operation on a [=database=] is done using a <dfn>request</dfn>. Every request represents one
operation.

<div dfn-for=request>

A [=/request=] has a <dfn>processed flag</dfn> which is initially false.
This flag is set to true when the operation associated with the request has been executed.

A [=/request=] is said to be <dfn>processed</dfn> when its [=request/processed flag=] is true.

A [=/request=] has a <dfn>done flag</dfn> which is initially false.
This flag is set to true when the result of the operation associated with the request is available.

A [=/request=] has a <dfn>source</dfn> object.

A [=/request=] has a <dfn>result</dfn> and an <dfn>error</dfn>, neither
of which are accessible until its [=request/done flag=] is true.

A [=/request=] has a <dfn>transaction</dfn> which is initially null.
This will be set when a request is <dfn>placed</dfn> against a
[=/transaction=] using the steps to [=asynchronously execute a
request=].

When a request is made, a new [=/request=] is returned with its [=request/done
flag=] set to false. If a request completes successfully, its [=request/done flag=]
is set to true, its [=request/result=] is set to the result of the request,
and an event with type <dfn event>`success`</dfn> is fired at the
[=/request=].

If an error occurs while performing the operation, the request's [=request/done flag=]
is set to true, the request's [=request/error=] is set to the error, and an event with
type <dfn event>`error`</dfn> is fired at the request.

A [=/request=]'s [=get the parent=] algorithm returns the request's
[=request/transaction=].

<aside class=note>
  Requests are not typically re-used, but there are exceptions. When a
  [=cursor=] is iterated, the success of the iteration is reported
  on the same [=/request=] object used to open the cursor. And when
  an [=/upgrade transaction=] is necessary, the same [=open
  request=] is used for both the <a event>`upgradeneeded`</a>
  event and final result of the open operation itself. In some cases,
  the request's [=request/done flag=] will be set to false, then set to true again, and the
  [=request/result=] can change or [=request/error=] could be set instead.
</aside>

<!-- ============================================================ -->
### Open Requests ### {#open-requests}
<!-- ============================================================ -->

An <dfn>open request</dfn> is a special type of [=/request=] used
when opening a [=/connection=] or deleting a [=database=].
In addition to <a event>`success`</a> and <a event>`error`</a> events,
<dfn event>`blocked`</dfn> and <dfn event>`upgradeneeded`</dfn> events may be fired at an [=open
request=] to indicate progress.

The [=request/source=] of an [=open request=]
is always null.

The [=request/transaction=] of an [=open request=] is null
unless an <a event>`upgradeneeded`</a> event has been fired.

An [=open request=]'s [=get the parent=] algorithm returns null.

[=Open requests=] are processed in a <dfn>connection queue</dfn>.
The queue contains all [=open requests=] associated with an
[=/origin=] and a [=database/name=]. Requests added to the
[=connection queue=] processed in order and each request must run
to completion before the next request is processed. An open request
may be blocked on other [=/connections=], requiring those
connections to [=connection/close=] before the request can complete and allow
further requests to be processed.

<aside class=note>
  A [=connection queue=] is not a [=task queue=] associated with
  an [=event loop=], as the requests are processed outside any
  specific [=/browsing context=]. The delivery of events to
  completed [=open request=] still goes through a [=task queue=]
  associated with the [=event loop=] of the context where the
  request was made.
</aside>

</div>

<!-- ============================================================ -->
## Key Range ## {#range-construct}
<!-- ============================================================ -->

Records can be retrieved from [=/object stores=] and [=/indexes=]
using either [=/keys=] or [=key ranges=]. A <dfn>key range</dfn> is a
continuous interval over some data type used for keys.

<div dfn-for="key range">

A [=key range=] has an associated <dfn>lower bound</dfn> (null or a
[=/key=]).

A [=key range=] has an associated <dfn>upper bound</dfn> (null or a
[=/key=]).

A [=key range=] has an associated <dfn>lower open flag</dfn>.
Unless otherwise stated it is false.

A [=key range=] has an associated <dfn>upper open flag</dfn>.
Unless otherwise stated it is false.

A [=key range=] may have a [=lower bound=] [=equal to=] its
[=upper bound=]. A [=key range=] must not have a [=lower
bound=] [=greater than=] its [=upper bound=].

</div>

A [=key range=] <dfn>containing only</dfn> |key| has both
[=lower bound=] and [=upper bound=] equal to |key|.

A |key| is <dfn lt="in">in a key range</dfn> |range| if both of the following
conditions are fulfilled:

* The |range|'s [=key range/lower bound=] is null, or it is [=less than=]
    |key|, or it is both [=equal to=] |key| and
    the |range|'s [=key range/lower open flag=] is false.

* The |range|'s [=key range/upper bound=] is null, or it is [=greater than=]
    |key|, or it is both [=equal to=] |key| and
    the |range|'s [=key range/upper open flag=] is false.

<aside class=note>

  * If a [=key range=]'s [=key range/lower open flag=] is false, the
    [=lower bound=] [=/key=] of the [=key range=] is included
    in the range itself.

  * If a [=key range=]'s [=key range/lower open flag=] is true, the
    [=lower bound=] [=/key=] of the [=key range=] is excluded
    from the range itself.

  * If a [=key range=]'s [=key range/upper open flag=] is false, the
    [=upper bound=] [=/key=] of the [=key range=] is included
    in the range itself.

  * If a [=key range=]'s [=key range/upper open flag=] is true, the
    [=upper bound=] [=/key=] of the [=key range=] is excluded
    from the range itself.

</aside>

An <dfn>unbounded key range</dfn> is a [=key range=] that has both
[=lower bound=] and [=upper bound=] equal to null. All
[=/keys=] are [=in=] an [=unbounded key
range=].

<div class=algorithm>

To <dfn>convert a value to a key range</dfn> with
|value| and optional |null disallowed flag|, run these steps:

1. If |value| is a [=key range=], return |value|.

1. If |value| is undefined or is null, then [=throw=] a
    "{{DataError}}" {{DOMException}} if |null disallowed flag| is true, or return an
    [=unbounded key range=] otherwise.

1. Let |key| be the result of running [=convert
    a value to a key=] with |value|. Rethrow any exceptions.

1. If |key| is invalid, [=throw=] a "{{DataError}}" {{DOMException}}.

1. Return a [=key range=] [=containing only=] |key|.

</div>

<!-- ============================================================ -->
## Cursor ## {#cursor-construct}
<!-- ============================================================ -->

A <dfn>cursor</dfn> is used to iterate over a range of records in an
[=/index=] or an [=/object store=] in a specific direction.

<div dfn-for=cursor>

A [=cursor=] has a <dfn>transaction</dfn>, the [=/transaction=]
that was [=transaction/active=] when the cursor was created.

A [=cursor=] has a <dfn>range</dfn> of records in either an
[=/index=] or an [=/object store=].

A [=cursor=] has a <dfn>source</dfn> that indicates which [=/index=]
or an [=/object store=] is associated with the records over which
the [=cursor=] is iterating.

A [=cursor=] has a <dfn>direction</dfn> that determines whether it
moves in monotonically increasing or decreasing order of the
[=object-store/record=] keys when iterated, and if it skips duplicated values
when iterating indexes. The direction of a cursor also determines if
the cursor initial position is at the start of its
[=cursor/source=] or at its end. A cursor's
[=cursor/direction=] is one of the following:

: {{"next"}}
::
    This direction causes the cursor to be opened at the start of the
    [=cursor/source=]. When iterated, the [=cursor=] should yield all
    records, including duplicates, in monotonically increasing order
    of keys.

: {{"nextunique"}}
::
    This direction causes the cursor to be opened at the start of the
    [=cursor/source=]. When iterated, the [=cursor=] should not yield
    records with the same key, but otherwise yield all records, in
    monotonically increasing order of keys. For every key with
    duplicate values, only the first record is yielded. When the
    [=cursor/source=] is an [=/object store=] or an [=/index=] with
    its [=unique flag=] set to true, this direction has exactly the same
    behavior as {{"next"}}.

: {{"prev"}}
::
    This direction causes the cursor to be opened at the end of the
    [=cursor/source=]. When iterated, the [=cursor=] should yield all
    records, including duplicates, in monotonically decreasing order
    of keys.

: {{"prevunique"}}
::
    This direction causes the cursor to be opened at the end of the
    [=cursor/source=]. When iterated, the [=cursor=] should not
    yield records with the same key, but otherwise yield all records,
    in monotonically decreasing order of keys. For every key with
    duplicate values, only the first record is yielded. When the
    [=cursor/source=] is an [=/object store=] or an
    [=/index=] with its [=unique flag=] set to true, this direction
    has exactly the same behavior as {{"prev"}}.

A [=cursor=] has a <dfn>position</dfn> within its range. It is
possible for the list of records which the cursor is iterating over to
change before the full [=cursor/range=] of the cursor has been iterated.
In order to handle this, cursors maintain their [=cursor/position=] not as
an index, but rather as a [=/key=] of the previously returned
record. For a forward iterating cursor, the next time the cursor is
asked to iterate to the next record it returns the record with the
lowest [=/key=] [=greater than=] the one previously
returned. For a backwards iterating cursor, the situation is opposite
and it returns the record with the highest [=/key=] [=less
than=] the one previously returned.

For cursors iterating indexes the situation is a little bit more
complicated since multiple records can have the same key and are
therefore also sorted by [=/value=]. When iterating indexes the
[=cursor=] also has an <dfn>object store position</dfn>, which
indicates the [=/value=] of the previously found [=object-store/record=] in
the index. Both [=cursor/position=] and the [=object store position=]
are used when finding the next appropriate record.

A [=cursor=] has a <dfn>key</dfn> and a <dfn>value</dfn> which
represent the [=/key=] and the [=/value=] of the last iterated
[=object-store/record=].

A [=cursor=] has a <dfn>got value flag</dfn>. When this flag is false,
the cursor is either in the process of loading the next value or it
has reached the end of its [=cursor/range=]. When it is true, it indicates
that the cursor is currently holding a value and that it is ready to
iterate to the next one.

If the [=cursor/source=] of a cursor is an [=/object store=], the
<dfn>effective object store</dfn> of the cursor is that object store
and the <dfn>effective key</dfn> of the cursor is the cursor's
[=cursor/position=]. If the [=cursor/source=] of a cursor is an [=/index=],
the [=effective object store=] of the cursor is that index's
[=referenced=] object store and the [=effective key=] is the cursor's
[=object store position=].

A [=cursor=] has a <dfn>request</dfn>, which is the [=/request=] used
to open the cursor.

A [=cursor=] also has a <dfn>key only flag</dfn>, that indicates
whether the cursor's [=cursor/value=] is exposed via the API.

</div>

<!-- ============================================================ -->
## Key Generators ## {#key-generator-construct}
<!-- ============================================================ -->

When a [=/object store=] is created it can be specified to use a
<dfn>key generator</dfn>. A key generator is used to generate keys
for records inserted into an object store if not otherwise specified.

<div dfn-for="key generator">

A [=key generator=] has a <dfn>current number</dfn>. The
[=key generator/current number=] is always a positive integer less
than or equal to 2<sup>53</sup> (9007199254740992) + 1. The initial value
of a [=key generator=]'s [=key generator/current number=] is 1, set
when the associated [=/object store=] is created. The
[=key generator/current number=] is incremented as keys are generated,
and may be updated to a specific value by using explicit keys.

</div>

<aside class=note>
  Every object store that uses key generators uses a separate
  generator. That is, interacting with one object store never affects
  the key generator of any other object store.
</aside>

Modifying a key generator's [=key generator/current number=] is considered part
of a database operation. This means that if the operation fails
and the operation is reverted, the [=key generator/current number=] is
reverted to the value it had before the operation started. This
applies both to modifications that happen due to the [=key generator/current
number=] getting increased by 1 when the key generator is used,
and to modifications that happen due to a [=object-store/record=] being
stored with a key value specified in the call to store the
[=object-store/record=].

Likewise, if a [=/transaction=] is aborted, the [=key generator/current
number=] of the key generator for each [=/object store=] in
the transaction's [=transaction/scope=] is reverted to the value it had
before the [=/transaction=] was started.

The [=key generator/current number=] for a key generator never decreases, other
than as a result of database operations being reverted. Deleting a
[=object-store/record=] from an [=/object store=] never affects the
object store's key generator. Even clearing all records from an
object store, for example using the {{IDBObjectStore/clear()}} method, does not
affect the [=key generator/current number=] of the object store's key
generator.

When a [=object-store/record=] is stored and a [=/key=] is not specified
in the call to store the record, a key is generated.

<div class=algorithm>

  To <dfn>generate a key</dfn> for an [=/object store=] |store|, run these steps:

  1. Let |generator| be |store|'s [=key generator=].

  1. Let |key| be |generator|'s [=key generator/current number=].

  1. If |key| is greater than 2<sup>53</sup> (9007199254740992), then return failure.

  1. Increase |generator|'s [=key generator/current number=] by 1.

  1. Return |key|.

</div>

When a [=object-store/record=] is stored and a [=/key=] is specified
in the call to store the record, the associated [=key generator=] may
be updated.

<div class=algorithm>

  To <dfn>possibly update the key generator</dfn> for an [=/object store=] |store| with |key|,
  run these steps:

  1. If the [=key/type=] of |key| is not *number*, abort these steps.

  1. Let |value| be the [=key/value=] of |key|.

  1. Let |value| be the minimum of |value| and 2<sup>53</sup> (9007199254740992).

  1. Let |value| be the largest integer not greater than |value|.

  1. Let |generator| be |store|'s [=key generator=].

  1. If |value| is greater than or equal to |generator|'s [=key generator/current number=],
      then set |generator|'s [=key generator/current number=] to |value| + 1.

</div>

<aside class=note>
  A key can be specified both for object stores which use
  [=in-line keys=], by setting the property on the stored value
  which the object store's [=object-store/key path=] points to,
  and for object stores which use [=out-of-line keys=], by passing
  a key argument to the call to store the [=object-store/record=].

  Only specified keys of [=key/type=] *number* can affect the
  [=key generator/current number=] of the key generator. Keys of [=key/type=]
  *date*, *array* (regardless of the other keys they
  contain), *binary*, or *string* (regardless of whether
  they could be parsed as numbers) have no effect on the [=key generator/current
  number=] of the key generator. Keys of [=key/type=]
  *number* with [=key/value=] less than 1 do not affect the
  [=key generator/current number=] since they are always lower than the
  [=key generator/current number=].
</aside>

When the [=key generator/current number=] of a key generator reaches above the
value 2<sup>53</sup> (9007199254740992) any subsequent attempts to use the
key generator to generate a new [=/key=] will result in a
"{{ConstraintError}}" {{DOMException}}. It is still possible to insert
[=object-store/records=] into the object store by specifying an explicit
key, however the only way to use a key generator again for such records
is to delete the object store and create a new one.

<aside class=note>
  This limit arises because integers greater than 9007199254740992
  cannot be uniquely represented as ECMAScript [=Numbers=].
  As an example, `9007199254740992 + 1 === 9007199254740992`
  in ECMAScript.

  As long as key generators are used in a normal fashion this limit will
  not be a problem. If you generate a new key 1000 times per
  second day and night, you won't run into this limit for over
  285000 years.
</aside>

A practical result of this is that the first key generated for an
object store is always 1 (unless a higher numeric key is inserted
first) and the key generated for an object store is always a positive
integer higher than the highest numeric key in the store. The same key
is never generated twice for the same object store unless a
transaction is rolled back.

<aside class=example id=example-key-generator>

Each object store gets its own key generator:

```js
store1 = db.createObjectStore("store1", { autoIncrement: true });
store1.put("a"); // Will get key 1
store2 = db.createObjectStore("store2", { autoIncrement: true });
store2.put("a"); // Will get key 1
store1.put("b"); // Will get key 2
store2.put("b"); // Will get key 2
```

If an insertion fails due to constraint violations or IO error, the
key generator is not updated.

```js
transaction.onerror = function(e) { e.preventDefault() };
store = db.createObjectStore("store1", { autoIncrement: true });
index = store.createIndex("index1", "ix", { unique: true });
store.put({ ix: "a"}); // Will get key 1
store.put({ ix: "a"}); // Will fail
store.put({ ix: "b"}); // Will get key 2
```

Removing items from an objectStore never affects the key generator.
Including when {{IDBObjectStore/clear()}} is called.

```js
store = db.createObjectStore("store1", { autoIncrement: true });
store.put("a"); // Will get key 1
store.delete(1);
store.put("b"); // Will get key 2
store.clear();
store.put("c"); // Will get key 3
store.delete(IDBKeyRange.lowerBound(0));
store.put("d"); // Will get key 4
```

Inserting an item with an explicit key affects the key generator if,
and only if, the key is numeric and higher than the last generated
key.

```js
store = db.createObjectStore("store1", { autoIncrement: true });
store.put("a"); // Will get key 1
store.put("b", 3); // Will use key 3
store.put("c"); // Will get key 4
store.put("d", -10); // Will use key -10
store.put("e"); // Will get key 5
store.put("f", 6.00001); // Will use key 6.0001
store.put("g"); // Will get key 7
store.put("f", 8.9999); // Will use key 8.9999
store.put("g"); // Will get key 9
store.put("h", "foo"); // Will use key "foo"
store.put("i"); // Will get key 10
store.put("j", [1000]); // Will use key [1000]
store.put("k"); // Will get key 11
// All of these would behave the same if the objectStore used a
// keyPath and the explicit key was passed inline in the object
```

Aborting a transaction rolls back any increases to the key generator
which happened during the transaction. This is to make all rollbacks
consistent since rollbacks that happen due to crash never has a chance
to commit the increased key generator value.

```js
db.createObjectStore("store", { autoIncrement: true });
trans1 = db.transaction(["store"], "readwrite");
store_t1 = trans1.objectStore("store");
store_t1.put("a"); // Will get key 1
store_t1.put("b"); // Will get key 2
trans1.abort();
trans2 = db.transaction(["store"], "readwrite");
store_t2 = trans2.objectStore("store");
store_t2.put("c"); // Will get key 1
store_t2.put("d"); // Will get key 2
```
</aside>

<aside class=example id=example-inline-keygen>

The following examples illustrate the different behaviors when trying
to use in-line [=/keys=] and [=key generators=] to save an object
to an [=/object store=].

If the following conditions are true:

* The [=/object store=] has a [=key generator=].

* There is no in-line value for the [=object-store/key path=]
    property.

Then the value provided by the [=key generator=] is used to populate
the key value. In the example below the [=object-store/key path=] for
the object store is "`foo.bar`". The actual object has no
value for the `bar` property, `{ foo: {} }`.
When the object is saved in the [=/object store=] the `bar`
property is assigned a value of 1 because that is the next [=/key=]
generated by the [=key generator=].

```js
const store = db.createObjectStore("store", { keyPath: "foo.bar",
                                              autoIncrement: true });
store.put({ foo: {} }).onsuccess = function(e) {
  const key = e.target.result;
  console.assert(key === 1);
};
```

If the following conditions are true:

* The [=/object store=] has a [=key generator=].

* There is a value for the [=object-store/key path=]
    property.

Then the value associated with the [=object-store/key path=]
property is used. The auto-generated [=/key=] is not used. In the
example below the [=object-store/key path=] for the [=/object
store=] is "`foo.bar`". The actual object has a value of
10 for the `bar` property, `{ foo: { bar: 10}
}`. When the object is saved in the [=/object store=] the
`bar` property keeps its value of 10, because that is the
key value.

```js
const store = db.createObjectStore("store", { keyPath: "foo.bar",
                                              autoIncrement: true });
store.put({ foo: { bar: 10 } }).onsuccess = function(e) {
  const key = e.target.result;
  console.assert(key === 10);
};
```

The following example illustrates the scenario when the specified
in-line [=/key=] is defined through a [=object-store/key
path=] but there is no property matching it. The value provided by
the [=key generator=] is then used to populate the key value and
the system is responsible for creating as many properties as it
requires to suffice the property dependencies on the hierarchy chain.
In the example below the [=object-store/key path=] for the
[=/object store=] is "`foo.bar.baz`". The actual
object has no value for the `foo` property, `{ zip: {}
}`. When the object is saved in the [=/object store=]
the `foo`, `bar`, and `baz`
properties are created each as a child of the other until a value for
`foo.bar.baz` can be assigned. The value for
`foo.bar.baz` is the next key generated by the object
store.

```js
const store = db.createObjectStore("store", { keyPath: "foo.bar.baz",
                                              autoIncrement: true });
store.put({ zip: {} }).onsuccess = function(e) {
  const key = e.target.result;
  console.assert(key === 1);
  store.get(key).onsuccess = function(e) {
    const value = e.target.result;
    // value will be: { zip: {}, foo: { bar: { baz: 1 } } }
    console.assert(value.foo.bar.baz === 1);
  };
};
```

Attempting to store a property on a primitive value will fail and
throw an error. In the first example below the [=object-store/key
path=] for the object store is "`foo`". The actual object
is a primitive with the value, `4`. Trying to define a
property on that primitive value fails. The same is true for arrays.
Properties are not allowed on an array. In the second example below,
the actual object is an array, `[10]`. Trying to define a
property on the array fails.

```js
const store = db.createObjectStore("store", { keyPath: "foo", autoIncrement: true });

// The key generation will attempt to create and store the key path
// property on this primitive.
store.put(4); // will throw DataError

// The key generation will attempt to create and store the key path
// property on this array.
store.put([10]); // will throw DataError
```
</aside>


<!-- ============================================================ -->
# Exceptions # {#exceptions}
<!-- ============================================================ -->

Each of the exceptions used in this document is a
{{DOMException}} with a specific type. The exception types and
properties such as legacy code value are defined in [[!WEBIDL]].

The table below lists the {{DOMException}}s used in this
document along with a description of the exception type's
usage.

<table class=props>
  <tr>
    <th>Type</th>
    <th>Description</th>
  </tr>
    <tr>
    <td>{{AbortError}}</td>
    <td>A request was aborted.</td>
  </tr>
  <tr>
    <td>{{ConstraintError}}</td>
    <td>
      A mutation operation in the transaction failed because a
      constraint was not satisfied.
    </td>
  </tr>
  <tr>
    <td>{{DataCloneError}}</td>
    <td>
      The data being stored could not be cloned by the internal
      structured cloning algorithm.
    </td>
  </tr>
  <tr>
    <td>{{DataError}}</td>
    <td>Data provided to an operation does not meet requirements.</td>
  </tr>
  <tr>
    <td>{{InvalidAccessError}}</td>
    <td>An invalid operation was performed on an object.</td>
  </tr>
  <tr>
    <td>{{InvalidStateError}}</td>
    <td>
      An operation was called on an object on which it is not allowed
      or at a time when it is not allowed, or if a request is made on
      a source object that has been deleted or removed.
    </td>
  </tr>
  <tr>
    <td>{{NotFoundError}}</td>
    <td>
      The operation failed because the requested database object could
      not be found.
    </td>
  </tr>
  <tr>
    <td>{{QuotaExceededError}}</td>
    <td>
      The operation failed because there was not enough remaining
      storage space, or the storage quota was reached and the user
      declined to give more space to the database.
    </td>
  </tr>
  <tr>
    <td>{{SyntaxError}}</td>
    <td>The keyPath argument contains an invalid key path.</td>
  </tr>
  <tr>
    <td>{{ReadOnlyError}}</td>
    <td>The mutating operation was attempted in a read-only transaction.</td>
  </tr>
  <tr>
    <td>{{TransactionInactiveError}}</td>
    <td>
      A request was placed against a transaction which is currently
      not active, or which is finished.
    </td>
  </tr>
  <tr>
    <td>{{UnknownError}}</td>
    <td>
      The operation failed for reasons unrelated to the database
      itself and not covered by any other errors.
    </td>
  </tr>
  <tr>
    <td>{{VersionError}}</td>
    <td>
      An attempt was made to open a database using a lower version
      than the existing version.
    </td>
  </tr>
</table>

<aside class=note>
  Given that multiple Indexed DB operations can throw the same type of
  error, and that even a single operation can throw the same type of
  error for multiple reasons, implementations are encouraged to
  provide more specific messages to enable developers to identify the
  cause of errors.
</aside>


<!-- ============================================================ -->
# API # {#async-api}
<!-- ============================================================ -->

The API methods return without blocking the calling thread. All
asynchronous operations immediately return an {{IDBRequest}}
instance. This object does not initially contain any information about
the result of the operation. Once information becomes available, an
event is fired on the request and the information becomes available
through the properties of the {{IDBRequest}} instance.

The <span>task source</span> for these tasks is the <dfn id=database-access-task-source export>database access task source</dfn>.


<!-- ============================================================ -->
## The {{IDBRequest}} interface ## {#request-api}
<!-- ============================================================ -->

The {{IDBRequest}} interface provides the means to access results of
asynchronous requests to [=databases=] and [=database=] objects using
[=event handler IDL attributes=] [[!HTML]].

Every method for making asynchronous requests returns an
{{IDBRequest}} object that communicates back to the requesting
application through events. This design means that any number of
requests can be active on any [=database=] at a time.

<aside class=example id=example-async-requests>

In the following example, we open a [=database=] asynchronously.
Various event handlers are registered for responding to various
situations.

```js
const request = indexedDB.open('AddressBook', 15);
request.onsuccess = function(evt) {...};
request.onerror = function(evt) {...};
```
</aside>

<xmp class=idl>
[Exposed=(Window,Worker)]
interface IDBRequest : EventTarget {
  readonly attribute any result;
  readonly attribute DOMException? error;
  readonly attribute (IDBObjectStore or IDBIndex or IDBCursor)? source;
  readonly attribute IDBTransaction? transaction;
  readonly attribute IDBRequestReadyState readyState;

  // Event handlers:
  attribute EventHandler onsuccess;
  attribute EventHandler onerror;
};

enum IDBRequestReadyState {
  "pending",
  "done"
};
</xmp>

<dl class="domintro note">
    : |request| . {{IDBRequest/result}}
    ::
        When a request is completed, returns the [=request/result=],
        or `undefined` if the request failed. Throws a
        "{{InvalidStateError}}" {{DOMException}} if the request is still pending.

    : |request| . {{IDBRequest/error}}
    ::
        When a request is completed, returns the [=request/error=] (a
        {{DOMException}}), or null if the request succeeded. Throws
        a "{{InvalidStateError}}" {{DOMException}} if the request is still pending.

    : |request| . {{IDBRequest/source}}
    ::
        Returns the {{IDBObjectStore}}, {{IDBIndex}}, or {{IDBCursor}}
        the request was made against, or null if it was an [=open
        request=].

    : |request| . {{IDBRequest/transaction}}
    ::
        Returns the {{IDBTransaction}} the request was made within.
        If this as an [=open request=], then it returns an
        [=/upgrade transaction=] while it is running, or null otherwise.

    : |request| . {{IDBRequest/readyState}}
    ::
        Returns {{"pending"}} until a request is complete,
        then returns {{"done"}}.
</dl>

The <dfn attribute for=IDBRequest>result</dfn> attribute's getter must
[=throw=] an "{{InvalidStateError}}" {{DOMException}} if **this**'s [=request/done flag=] is
false. Otherwise, the attribute's getter must return **this**'s [=request/result=], or undefined if the
request resulted in an error.


The <dfn attribute for=IDBRequest>error</dfn> attribute's getter must
[=throw=] an "{{InvalidStateError}}" {{DOMException}} if **this**'s [=request/done flag=] is false.
Otherwise, the attribute's getter must return **this**'s [=request/error=],
or null if no error occurred.

The <dfn attribute for=IDBRequest>source</dfn> attribute's getter must
return **this**'s [=request/source=], or null if no
[=request/source=] is set.

The <dfn attribute for=IDBRequest>transaction</dfn> attribute's getter
must return **this**'s [=request/transaction=]. This
property can be null for certain requests, such as for [=/requests=]
returned from {{IDBFactory/open()}}.

The <dfn attribute for=IDBRequest>readyState</dfn> attribute's getter
must return {{"pending"}} if **this**'s [=request/done flag=] is false, and
{{"done"}} otherwise.


The <dfn attribute for=IDBRequest>onsuccess</dfn> attribute is the
event handler for the <a event>`success`</a> event.

The <dfn attribute for=IDBRequest>onerror</dfn> attribute is the event
handler for the <a event>`error`</a> event.


Methods on {{IDBDatabase}} that return a [=open request=] use an
extended interface to allow listening to the
<a event>`blocked`</a> and <a event>`upgradeneeded`</a> events.

<xmp class=idl>
[Exposed=(Window,Worker)]
interface IDBOpenDBRequest : IDBRequest {
  // Event handlers:
  attribute EventHandler onblocked;
  attribute EventHandler onupgradeneeded;
};
</xmp>

The <dfn attribute for=IDBOpenDBRequest>onblocked</dfn> attribute is
the event handler for the <a event>`blocked`</a> event.

The <dfn attribute for=IDBOpenDBRequest>onupgradeneeded</dfn>
attribute is the event handler for the
<a event>`upgradeneeded`</a> event.


<!-- ============================================================ -->
## Event interfaces ## {#events}
<!-- ============================================================ -->

This specification fires events with the following custom interfaces:

<xmp class=idl>
[Exposed=(Window,Worker)]
interface IDBVersionChangeEvent : Event {
  constructor(DOMString type, optional IDBVersionChangeEventInit eventInitDict = {});
  readonly attribute unsigned long long oldVersion;
  readonly attribute unsigned long long? newVersion;
};

dictionary IDBVersionChangeEventInit : EventInit {
  unsigned long long oldVersion = 0;
  unsigned long long? newVersion = null;
};
</xmp>

The <dfn attribute for=IDBVersionChangeEvent>oldVersion</dfn>
attribute getter returns the previous version of the database.


The <dfn attribute for=IDBVersionChangeEvent>newVersion</dfn>
attribute getter returns the new version of the database, or null if
the database is being deleted. See the steps to [=run an upgrade
transaction=].

Events are constructed as defined in [[DOM#constructing-events]].

<div class=algorithm>

  To <dfn>fire a version change event</dfn> named |e| at |target| given
  |oldVersion| and |newVersion|, run these steps:

  1. Let |event| be the result of [=creating an event=] using
      {{IDBVersionChangeEvent}}.
  1. Set |event|'s {{Event/type}} attribute to |e|.
  1. Set |event|'s {{Event/bubbles}} and {{Event/cancelable}} attributes to false.
  1. Set |event|'s {{IDBVersionChangeEvent/oldVersion}} attribute to |oldVersion|.
  1. Set |event|'s {{IDBVersionChangeEvent/newVersion}} attribute to |newVersion|.
  1. Let |legacyOutputDidListenersThrowFlag| be false.
  1. [=Dispatch=] |event| at |target| with |legacyOutputDidListenersThrowFlag|.
  1. Return |legacyOutputDidListenersThrowFlag|.
      <aside class=note>
        The return value of this algorithm is not always used.
      </aside>

</div>


<!-- ============================================================ -->
## The {{IDBFactory}} interface ## {#factory-interface}
<!-- ============================================================ -->

[=Database=] objects are accessed through methods on the
{{IDBFactory}} interface. A single object implementing this
interface is present in the global scope of environments that support
Indexed DB operations.

<xmp class=idl id=global-scope>
partial interface mixin WindowOrWorkerGlobalScope {
  [SameObject] readonly attribute IDBFactory indexedDB;
};
</xmp>

The <dfn attribute for=WindowOrWorkerGlobalScope>indexedDB</dfn>
attribute provides applications a mechanism for accessing capabilities
of indexed databases.

<xmp class=idl>
[Exposed=(Window,Worker)]
interface IDBFactory {
  [NewObject] IDBOpenDBRequest open(DOMString name,
                                    optional [EnforceRange] unsigned long long version);
  [NewObject] IDBOpenDBRequest deleteDatabase(DOMString name);

  Promise<sequence<IDBDatabaseInfo>> databases();

  short cmp(any first, any second);
};

dictionary IDBDatabaseInfo {
  DOMString name;
  unsigned long long version;
};
</xmp>


<dl class="domintro note">
    : |request| = indexedDB .
        {{IDBFactory/open()|open}}(|name|)
    ::
        Attempts to open a [=/connection=] to the named [=/database=]
        with the current version, or 1 if it does not already exist.
        If the request is successful |request|'s
        {{IDBRequest/result}} will be the [=/connection=].

    : |request| = indexedDB .
        {{IDBFactory/open()|open}}(|name|, |version|)
    ::
        Attempts to open a [=/connection=] to the named [=/database=]
        with the specified version. If the database already exists
        with a lower version and there are open [=/connections=]
        that don't close in response to a
        <a event>`versionchange`</a> event, the request will be
        blocked until they all close, then an upgrade
        will occur. If the database already exists with a higher
        version the request will fail. If the request is
        successful |request|'s {{IDBRequest/result}} will
        be the [=/connection=].

    : |request| = indexedDB .
        {{IDBFactory/deleteDatabase()|deleteDatabase}}(|name|)
    ::
        Attempts to delete the named [=/database=]. If the
        database already exists and there are open
        [=/connections=] that don't close in response to a
        <a event>`versionchange`</a> event, the request will be
        blocked until they all close. If the request
        is successful |request|'s {{IDBRequest/result}}
        will be null.

    : |result| = await indexedDB . {{IDBFactory/databases()|databases}}()
    ::
        Returns a promise which resolves to a list of objects giving a snapshot
        of the names and versions of databases within the origin.

        This API is intended for web applications to introspect the use of databases,
        for example to clean up from earlier versions of a site's code. Note that
        the result is a snapshot; there are no guarantees about the sequencing of the
        collection of the data or the delivery of the response with respect to requests
        to create, upgrade, or delete databases by this context or others.
</dl>

<div class=algorithm>

The <dfn method for=IDBFactory>open(|name|, |version|)</dfn> method,
when invoked, must run these steps:

1. If |version| is 0 (zero), [=throw=] a [=TypeError=].

1. Let |origin| be the [=/origin=] of the global scope used to access **this**.

1. If |origin| is an [=opaque origin=], [=throw=] a
    "{{SecurityError}}" {{DOMException}} and abort these steps.

1. Let |request| be a new [=open request=].

1. Run these steps [=in parallel=]:

    1. Let |result| be the result of running
        [=open a database=], with |origin|,
        |name|, |version| if given and undefined
        otherwise, and |request|.

        <details class=note>
          <summary>What happens if |version| is not given?</summary>
          If |version| is not given and a [=database=]
          with that name already exists, a connection will be opened
          without changing the [=database/version=]. If
          |version| is not given and no [=database=] with
          that name exists, a new [=database=] will be created with
          [=database/version=] equal to 1.
        </details>

    1. [=Queue a task=] to run these steps:

        1. If |result| is an error, then:

            1. Set |request|'s [=request/result=] to undefined.
            1. Set |request|'s [=request/error=] to |result|.
            1. Set |request|'s [=request/done flag=] to true.
            1. [=Fire an event=] named <a event>`error`</a> at |request| with its
                {{Event/bubbles}} and {{Event/cancelable}} attributes initialized to true.

        1. Otherwise:

            1. Set |request|'s [=request/result=] to |result|.
            1. Set |request|'s [=request/done flag=] to true.
            1. [=Fire an event=] named <a event>`success`</a> at |request|.

            <aside class=note>
                If the steps above resulted in an [=/upgrade
                transaction=] being run, these steps will run after
                that transaction finishes. This ensures that in the
                case where another version upgrade is about to happen,
                the success event is fired on the connection first so
                that the script gets a chance to register a listener
                for the <a event>`versionchange`</a> event.
            </aside>

            <details class=note>
              <summary>
                Why aren't the steps to [=fire a success event=] or
                [=fire an error event=] used?
              </summary>
              There is no transaction associated with the request (at
              this point), so those steps &mdash; which activate an
              associated transaction before dispatch and deactivate
              the transaction after dispatch &mdash; do not apply.
            </details>

1. Return a new {{IDBOpenDBRequest}} object for |request|.

</div>

<div class=algorithm>

The <dfn method for=IDBFactory>deleteDatabase(|name|)</dfn> method,
when invoked, must run these steps:

1. Let |origin| be the [=/origin=] of the global scope used to access **this**.

1. If |origin| is an [=opaque origin=], [=throw=] a
    "{{SecurityError}}" {{DOMException}} and abort these steps.

1. Let |request| be a new [=open request=].

1. Run these steps [=in parallel=]:

    1. Let |result| be the result of running
        [=delete a database=], with |origin|,
        |name|, and |request|.

    1. Set |request|'s [=request/processed flag=] to true.

    1. [=Queue a task=] to run these steps:
        1. If |result| is an error,
            set |request|'s [=request/error=] to |result|,
            set |request|'s [=request/done flag=] to true,
            and [=fire an event=]
            named <a event>`error`</a> at |request| with
            its {{Event/bubbles}} and {{Event/cancelable}} attributes initialized to true.

        1. Otherwise,
            set |request|'s [=request/result=] to undefined,
            set |request|'s [=request/done flag=] to true,
            and [=fire a version change event=] named
            <a event>`success`</a> at [=/request=] with |result| and
            null.

            <details class=note>
              <summary>
                Why aren't the steps to [=fire a success event=] or
                [=fire an error event=] used?
              </summary>
              There is no transaction associated with the request, so
              those steps &mdash; which activate an associated
              transaction before dispatch and deactivate the
              transaction after dispatch &mdash; do not apply.

              Also, the <a event>`success`</a> event here is a
              {{IDBVersionChangeEvent}} which includes the
              {{IDBVersionChangeEvent/oldVersion}} and
              {{IDBVersionChangeEvent/newVersion}} details.
            </details>

1. Return a new {{IDBOpenDBRequest}} object for |request|.

</div>

<div class=algorithm>

The <dfn method for=IDBFactory>databases()</dfn> method,
when invoked, must run these steps:

1. Let |origin| be the [=/origin=] of the global scope used to access **this**.

1. If |origin| is an [=opaque origin=],
    then return [=/a promise rejected with=] a "{{SecurityError}}" {{DOMException}}.

1. Let |p| be [=/a new promise=].

1. Run these steps [=in parallel=]:

    1. Let |databases| be the [=/set=] of [=databases=] in |origin|.
        If this cannot be determined for any reason, then [=/reject=] |p| with
        an appropriate error (e.g. an "{{UnknownError}}" {{DOMException}})
        and terminate these steps.

    1. Let |result| be a new [=/list=].

    1. [=set/For each=] |db| of |databases|:

        1. Let |info| be a new {{IDBDatabaseInfo}} dictionary.
        1. Set |info|'s {{IDBDatabaseInfo/name}} dictionary member to |db|'s [=database/name=].
        1. Set |info|'s {{IDBDatabaseInfo/version}} dictionary member to |db|'s [=database/version=].
        1. [=list/Append=] |info| to |result|.

    1. [=/Resolve=] |p| with |result|.

1. Return |p|.

</div>

<aside class=advisement>
  &#x1F6A7;
  The {{IDBFactory/databases()}} method is new in this edition.
  &#x1F6A7;
</aside>

<dl class="domintro note">
    : |result| = indexedDB .
        {{IDBFactory/cmp()|cmp}}(|key1|, |key2|)
    ::
        Compares two values as [=/keys=]. Returns -1 if
        |key1| precedes |key2|, 1 if
        |key2| precedes |key1|, and 0 if
        the keys are equal.

        Throws a "{{DataError}}" {{DOMException}} if either input is not a valid [=/key=].
</dl>

<div class=algorithm>

The <dfn method for=IDBFactory>cmp(|first|, |second|)</dfn> method,
when invoked, must run these steps:

1. Let |a| be the result of running [=convert a
    value to a key=] with |first|. Rethrow any exceptions.

1. If |a| is invalid, [=throw=] a "{{DataError}}" {{DOMException}}.

1. Let |b| be the result of running [=convert a
    value to a key=] with |second|. Rethrow any exceptions.

1. If |b| is invalid, [=throw=] a "{{DataError}}" {{DOMException}}.

1. Return the results of running [=compare two keys=]
    with |a| and |b|.

</div>

<!-- ============================================================ -->
## The {{IDBDatabase}} interface ## {#database-interface}
<!-- ============================================================ -->

The {{IDBDatabase}}
interface represents a [=/connection=] to a [=database=].

An {{IDBDatabase}} object must not be garbage collected if its
associated [=/connection=]'s [=close pending flag=] is false and it
has one or more event listeners registers whose type is one of
<a event>`abort`</a>, <a event>`error`</a>, or <a event>`versionchange`</a>.
If an {{IDBDatabase}} object is garbage collected, the associated
[=/connection=] must be [=connection/closed=].

<xmp class=idl>
[Exposed=(Window,Worker)]
interface IDBDatabase : EventTarget {
  readonly attribute DOMString name;
  readonly attribute unsigned long long version;
  readonly attribute DOMStringList objectStoreNames;

  [NewObject] IDBTransaction transaction((DOMString or sequence<DOMString>) storeNames,
                                         optional IDBTransactionMode mode = "readonly");
  void close();

  [NewObject] IDBObjectStore createObjectStore(
    DOMString name,
    optional IDBObjectStoreParameters options = {});
  void deleteObjectStore(DOMString name);

  // Event handlers:
  attribute EventHandler onabort;
  attribute EventHandler onclose;
  attribute EventHandler onerror;
  attribute EventHandler onversionchange;
};

dictionary IDBObjectStoreParameters {
  (DOMString or sequence<DOMString>)? keyPath = null;
  boolean autoIncrement = false;
};
</xmp>

<dl class="domintro note">
    : |connection| . {{IDBDatabase/name}}
    :: Returns the [=database/name=] of the database.

    : |connection| . {{IDBDatabase/version}}
    :: Returns the [=database/version=] of the database.
</dl>

The <dfn attribute for=IDBDatabase>name</dfn> attribute's getter must
return **this**'s associated [=database=]'s [=database/name=].
The attribute must return this name even if
**this**'s [=close pending flag=] is true. In
other words, the value of this attribute stays constant for the
lifetime of the {{IDBDatabase}} instance.


The <dfn attribute for=IDBDatabase>version</dfn> attribute's getter
must return **this**'s [=connection/version=].

<details class=note>
  <summary>
    Is this the same as the [=/database=]'s [=database/version=]?
  </summary>
  As long as the [=/connection=] is open, this is the same as the
  connected [=database=]'s [=database/version=]. But once the
  [=/connection=] has [=connection/closed=], this attribute will not
  reflect changes made with a later [=/upgrade transaction=].
</details>

<dl class="domintro note">
    : |connection| . {{IDBDatabase/objectStoreNames}}
    ::
        Returns a list of the names of [=/object stores=] in the database.

    : |store| = |connection| .
        {{IDBDatabase/createObjectStore()|createObjectStore}}(|name|
            [, |options|])
    ::
        Creates a new [=/object store=] with the given |name| and |options|
        and returns a new {{IDBObjectStore}}.

        Throws a "{{InvalidStateError}}" {{DOMException}} if not called within an
        [=/upgrade transaction=].

    : |connection| .
        {{IDBDatabase/deleteObjectStore()|deleteObjectStore}}(|name|)
    ::
        Deletes the [=/object store=] with the given |name|.

        Throws a "{{InvalidStateError}}" {{DOMException}} if not called within an
        [=/upgrade transaction=].
</dl>

The <dfn attribute for=IDBDatabase>objectStoreNames</dfn> attribute's
getter must return a {{DOMStringList}} associated with a [=sorted name list=] of the [=object-store/names=] of
the [=/object stores=] in **this**'s [=object store set=].

<details class=note>
  <summary>
    Is this the same as the [=database=]'s [=/object store=]
    [=object-store/names=]?
  </summary>
  As long as the [=/connection=] is open, this is the same as the
  connected [=database=]'s [=/object store=] [=object-store/names=].
  But once the [=/connection=] has [=connection/closed=], this attribute
  will not reflect changes made with a later [=/upgrade transaction=].
</details>


<div class=algorithm>

The <dfn method for=IDBDatabase>createObjectStore(|name|,
|options|)</dfn> method, when invoked, must run these steps:

1. Let |database| be **this**'s associated [=database=].

1. Let |transaction| be |database|'s [=database/upgrade transaction=]
    if it is not null, or [=throw=] an "{{InvalidStateError}}"
    {{DOMException}} otherwise.

1. If |transaction|'s [=transaction/state=] is not [=transaction/active=],
    then [=throw=] a "{{TransactionInactiveError}}" {{DOMException}}.

1. Let |keyPath| be |options|'s {{IDBObjectStoreParameters/keyPath}}
    member if it is not undefined or null, or null otherwise.

1. If |keyPath| is not null and is not a [=valid key
    path=], [=throw=] a "{{SyntaxError}}" {{DOMException}}.

1. If an [=/object store=] [=object-store/named=] |name| already
    exists in |database| [=throw=] a "{{ConstraintError}}" {{DOMException}}.

1. Let |autoIncrement| be |options|'s
    {{IDBObjectStoreParameters/autoIncrement}} member.

1. If |autoIncrement| is true and |keyPath| is an empty string or any
    sequence (empty or otherwise), [=throw=] an
    "{{InvalidAccessError}}" {{DOMException}}.

1. Let |store| be a new [=/object store=] in
    |database|. Set the created [=/object store=]'s
    [=object-store/name=] to |name|. If
    |autoIncrement| is true, then the created [=/object
    store=] uses a [=key generator=]. If |keyPath| is
    not null, set the created [=/object store=]'s
    [=object-store/key path=] to |keyPath|.

1. Return a new [=/object store handle=] associated with
    |store| and |transaction|.

</div>

This method creates and returns a new [=/object store=] with the given
name in the [=connected=] [=database=]. Note that this method must
only be called from within an [=/upgrade transaction=].

This method synchronously modifies the
{{IDBDatabase/objectStoreNames}} property on the {{IDBDatabase}}
instance on which it was called.

In some implementations it is possible for the implementation to run
into problems after queuing a task to create the [=/object store=]
after the {{createObjectStore()}} method has returned. For example in
implementations where metadata about the newly created [=/object
store=] is inserted into the database asynchronously, or where the
implementation might need to ask the user for permission for quota
reasons. Such implementations must still create and return an
{{IDBObjectStore}} object, and once the implementation determines that
creating the [=/object store=] has failed, it must abort the
transaction using the steps to [=abort a transaction=] using the
appropriate error. For example if creating the [=/object store=]
failed due to quota reasons, a "{{QuotaExceededError}}" {{DOMException}} must be used as
error.


<div class=algorithm>

The <dfn method for=IDBDatabase>deleteObjectStore(|name|)</dfn>
method, when invoked, must run these steps:

1. Let |database| be **this**'s associated [=database=].

1. Let |transaction| be |database|'s [=database/upgrade transaction=]
    if it is not null, or [=throw=] an "{{InvalidStateError}}"
    {{DOMException}} otherwise.

1. If |transaction|'s [=transaction/state=] is not [=transaction/active=],
    then [=throw=] a "{{TransactionInactiveError}}" {{DOMException}}.

1. Let |store| be the [=/object store=]
    [=object-store/named=] |name| in |database|,
    or [=throw=] a "{{NotFoundError}}" {{DOMException}} if none.

1. Remove |store| from **this**'s [=object store set=].

1. If there is an [=/object store handle=] associated with
    |store| and |transaction|, remove all entries from its
    [=object-store-handle/index set=].

1. Destroy |store|.

</div>

This method destroys the [=/object store=] with the given name in the
[=connected=] [=database=]. Note that this method must only be called
from within an [=/upgrade transaction=].

This method synchronously modifies the
{{IDBDatabase/objectStoreNames}} property on the {{IDBDatabase}}
instance on which it was called.


<dl class="domintro note">
    : |transaction| = |connection| .
        {{IDBDatabase/transaction()|transaction}}(|scope|
        [, |mode| = "readonly"])
    ::
        Returns a new [=/transaction=] with the given |mode|
        ({{"readonly"}} or {{"readwrite"}})
        and |scope| which can be a single [=/object store=]
        [=object-store/name=] or an array of
        [=object-store/names=].

    : |connection| . {{IDBDatabase/close()|close}}()
    ::
        Closes the [=/connection=] once all running [=/transactions=]
        have finished.
</dl>

<div class=algorithm>

The <dfn method for=IDBDatabase>transaction(|storeNames|,
|mode|)</dfn> method, when invoked, must run these steps:

1. If a running [=/upgrade transaction=] is associated with the [=/connection=],
    [=throw=] an "{{InvalidStateError}}" {{DOMException}}.

1. If **this**'s [=close pending flag=] is true, then [=throw=] an
    "{{InvalidStateError}}" {{DOMException}}.

1. Let |scope| be the set of unique strings in |storeNames| if it is a
    sequence, or a set containing one string equal to |storeNames|
    otherwise.

1. If any string in |scope| is not the name of an [=/object
    store=] in the [=connected=] [=database=], [=throw=] a
    "{{NotFoundError}}" {{DOMException}}.

1. If |scope| is empty, [=throw=] an "{{InvalidAccessError}}" {{DOMException}}.

1. If |mode| is not {{"readonly"}} or {{"readwrite"}},
    [=throw=] a [=TypeError=].

1. Let |transaction| be a newly [=transaction/created=] [=/transaction=] with
    |connection|, |mode| and the set of [=/object stores=] named in
    |scope|.

1. Set |transaction|'s [=transaction/cleanup event loop=] to the
    current [=event loop=].

1. Return an {{IDBTransaction}} object representing |transaction|.

</div>

<aside class=note>
  The created |transaction| will follow the [=transaction/lifetime=]
  rules.
</aside>


<div class=algorithm>

The <dfn method for=IDBDatabase>close()</dfn> method, when invoked,
must run these steps:

1. Run [=close a database connection=] with this
    [=/connection=].

</div>

<aside class=note>
The [=/connection=] will not actually [=connection/close=] until all outstanding [=/transactions=] have completed. Subsequent calls to {{IDBDatabase/close()}} will have no effect.
</aside>


The <dfn attribute for=IDBDatabase>onabort</dfn> attribute is the
event handler for the <a event>`abort`</a> event.

The <dfn attribute for=IDBDatabase>onclose</dfn> attribute is the
event handler for the <a event>`close`</a> event.

The <dfn attribute for=IDBDatabase>onerror</dfn> attribute is the
event handler for the <a event>`error`</a> event.

The <dfn attribute for=IDBDatabase>onversionchange</dfn> attribute is
the event handler for the <a event>`versionchange`</a> event.


<!-- ============================================================ -->
## The {{IDBObjectStore}} interface ## {#object-store-interface}
<!-- ============================================================ -->

The {{IDBObjectStore}}
interface represents an [=/object store handle=].

<xmp class=idl>
[Exposed=(Window,Worker)]
interface IDBObjectStore {
  attribute DOMString name;
  readonly attribute any keyPath;
  readonly attribute DOMStringList indexNames;
  [SameObject] readonly attribute IDBTransaction transaction;
  readonly attribute boolean autoIncrement;

  [NewObject] IDBRequest put(any value, optional any key);
  [NewObject] IDBRequest add(any value, optional any key);
  [NewObject] IDBRequest delete(any query);
  [NewObject] IDBRequest clear();
  [NewObject] IDBRequest get(any query);
  [NewObject] IDBRequest getKey(any query);
  [NewObject] IDBRequest getAll(optional any query,
                                optional [EnforceRange] unsigned long count);
  [NewObject] IDBRequest getAllKeys(optional any query,
                                    optional [EnforceRange] unsigned long count);
  [NewObject] IDBRequest count(optional any query);

  [NewObject] IDBRequest openCursor(optional any query,
                                    optional IDBCursorDirection direction = "next");
  [NewObject] IDBRequest openKeyCursor(optional any query,
                                       optional IDBCursorDirection direction = "next");

  IDBIndex index(DOMString name);

  [NewObject] IDBIndex createIndex(DOMString name,
                                   (DOMString or sequence<DOMString>) keyPath,
                                   optional IDBIndexParameters options = {});
  void deleteIndex(DOMString name);
};

dictionary IDBIndexParameters {
  boolean unique = false;
  boolean multiEntry = false;
};
</xmp>

<dl class="domintro note">
    : |store| . {{IDBObjectStore/name}}
    ::
        Returns the [=object-store/name=] of the store.

    : |store| . {{IDBObjectStore/name}} = |newName|
    ::
        Updates the [=object-store/name=] of the store to |newName|.

        Throws "{{InvalidStateError}}" {{DOMException}} if not called within an [=/upgrade
        transaction=].

    : |store| . {{IDBObjectStore/keyPath}}
    ::
        Returns the [=object-store/key path=] of the store, or null if none.

    : |list| . {{IDBObjectStore/indexNames}}
    ::
        Returns a list of the names of indexes in the store.

    : |store| . {{IDBObjectStore/transaction}}
    ::
        Returns the associated [=/transaction=].

    : |store| . {{IDBObjectStore/autoIncrement}}
    ::
        Returns true if the store has a [=key generator=], and false otherwise.
</dl>


The <dfn attribute for=IDBObjectStore>name</dfn> attribute's getter
must return **this**'s [=object-store/name=].

<details class=note>
  <summary>
    Is this the same as the [=/object store=]'s [=object-store/name=]?
  </summary>
  As long as the [=/transaction=] has not [=transaction/finished=],
  this is the same as the associated [=/object store=]'s
  [=object-store/name=]. But once the [=/transaction=] has
  [=transaction/finished=], this attribute will not reflect changes made with a
  later [=/upgrade transaction=].
</details>


<div class=algorithm>

The {{IDBObjectStore/name}} attribute's setter must run these steps:

1. Let |name| be the given value.

1. Let |transaction| be **this**'s [=object-store-handle/transaction=].

1. Let |store| be **this**'s [=object-store-handle/object store=].

1. If |store| has been deleted,
    [=throw=] an "{{InvalidStateError}}" {{DOMException}}.

1. If |transaction| is not an [=/upgrade transaction=],
    [=throw=] an "{{InvalidStateError}}" {{DOMException}}.

1. If |transaction|'s [=transaction/state=] is not [=transaction/active=],
    [=throw=] a "{{TransactionInactiveError}}" {{DOMException}}.

1. If |store|'s [=object-store/name=] is equal to |name|,
    terminate these steps.

1. If an [=/object store=] [=object-store/named=]
    |name| already exists in |store|'s [=database=], [=throw=] a
    "{{ConstraintError}}" {{DOMException}}.

1. Set |store|'s [=object-store/name=] to |name|.

1. Set **this**'s [=object-store-handle/name=] to |name|.

</div>


The <dfn attribute for=IDBObjectStore>keyPath</dfn> attribute's getter
must return **this**'s [=object-store-handle/object store=]'s [=object-store/key path=], or
null if none. The [=/key path=] is converted as a {{DOMString}} (if a
string) or a [=sequence&lt;DOMString&gt;=] (if a list of strings), per
[[!WEBIDL]].

The returned value is not the same instance that was used when the
[=/object store=] was created. However, if this attribute returns
an object (specifically an [=Array=]), it returns the same object
instance every time it is inspected. Changing the properties of the
object has no effect on the [=/object store=].


The <dfn attribute for=IDBObjectStore>indexNames</dfn> attribute's
getter must return a {{DOMStringList}} associated with a [=sorted name list=] of the [=index/names=]
of [=/indexes=] in **this**'s [=index set=].

<details class=note>
  <summary>
    Is this the same as [=/object store=]'s list
    of [=/index=] [=index/names=]?
  </summary>
  As long as the [=/transaction=] has not [=transaction/finished=],
  this is the same as the associated [=/object store=]'s list
  of [=/index=] [=index/names=]. But once the
  [=/transaction=] has [=transaction/finished=], this attribute will not
  reflect changes made with a later [=/upgrade transaction=].
</details>


The <dfn attribute for=IDBObjectStore>transaction</dfn> attribute's
getter must return **this**'s [=object-store-handle/transaction=].


The <dfn attribute for=IDBObjectStore>autoIncrement</dfn> attribute's
getter must return true if **this**'s [=object-store-handle/object store=] has a [=key generator=],
and false otherwise.


<div class=note>
  The following methods throw a "{{ReadOnlyError}}" {{DOMException}} if called within a
  [=read-only transaction=], and a "{{TransactionInactiveError}}" {{DOMException}} if
  called when the [=/transaction=] is not [=transaction/active=].

  <dl class=domintro>
    : |request| = |store|
          . {{IDBObjectStore/put()|put}}(|value| [, |key|])

    : |request| = |store|
          . {{IDBObjectStore/add()|add}}(|value| [, |key|])
    ::
        Adds or updates a [=object-store/record=] in |store| with the given |value|
        and |key|.

        If the store uses [=in-line keys=] and |key| is specified a
        "{{DataError}}" {{DOMException}} will be thrown.

        If {{IDBObjectStore/put()}} is used, any existing [=object-store/record=]
        with the [=/key=] will be replaced. If {{IDBObjectStore/add()}}
        is used, and if a [=object-store/record=] with the [=/key=] already exists
        the |request| will fail, with |request|'s {{IDBRequest/error}}
        set to a "{{ConstraintError}}" {{DOMException}}.

        If successful, |request|'s {{IDBRequest/result}} will be the
        [=object-store/record=]'s [=/key=].

    : |request| = |store| .
          {{IDBObjectStore/delete()|delete}}(|query|)
    ::
        Deletes [=object-store/records=] in |store| with the given
        [=/key=] or in the given [=key range=] in |query|.

        If successful, |request|'s {{IDBRequest/result}} will
        be `undefined`.

    : |request| = |store| . {{IDBObjectStore/clear()|clear}}()
    ::
        Deletes all [=object-store/records=] in |store|.

        If successful, |request|'s {{IDBRequest/result}} will
        be `undefined`.
  </dl>
</div>


The <dfn method for=IDBObjectStore>put(|value|, |key|)</dfn> method,
when invoked, must return the result of running [=add or
put=] with **this**, |value|, |key| and the |no-overwrite flag| false.

The <dfn method for=IDBObjectStore>add(|value|, |key|)</dfn> method,
when invoked, must return the result of running [=add or
put=] with **this**, |value|, |key| and the |no-overwrite flag| true.

<div class=algorithm>

To <dfn>add or put</dfn> with |handle|, |value|, |key|, and |no-overwrite flag|, run these steps:

1. Let |transaction| be |handle|'s
    [=object-store-handle/transaction=].

1. Let |store| be |handle|'s
    [=object-store-handle/object store=].

1. If |store| has been deleted,
    [=throw=] an "{{InvalidStateError}}" {{DOMException}}.

1. If |transaction|'s [=transaction/state=] is not [=transaction/active=],
    then [=throw=] a "{{TransactionInactiveError}}" {{DOMException}}.

1. If |transaction| is a [=read-only transaction=],
    [=throw=] a "{{ReadOnlyError}}" {{DOMException}}.

1. If |store| uses [=in-line keys=] and |key| was given,
    [=throw=] a "{{DataError}}" {{DOMException}}.

1. If |store| uses [=out-of-line keys=] and has no [=key
    generator=] and |key| was not given, [=throw=] a
    "{{DataError}}" {{DOMException}}.

1. If |key| was given, then:

    1. Let |r| be the result of running [=convert a
        value to a key=] with |key|. Rethrow any exceptions.

    1. If |r| is invalid, [=throw=] a "{{DataError}}" {{DOMException}}.

    1. Let |key| be |r|.

1. Let |targetRealm| be a user-agent defined [=Realm=].

1. Let |clone| be a [=clone=] of |value| in |targetRealm| during |transaction|.
    Rethrow any exceptions.

    <details class=note>
      <summary>Why create a copy of the value?</summary>
      The value is serialized when stored. Treating it as a copy
      here allows other algorithms in this specification to treat it as
      an ECMAScript value, but implementations can optimize this
      if the difference in behavior is not observable.
    </details>

1. If |store| uses [=in-line keys=], then:

    1. Let |kpk| be the result of running [=extract a
        key from a value using a key path=] with |clone| and
        |store|'s [=object-store/key path=]. Rethrow any
        exceptions.

    1. If |kpk| is invalid, [=throw=] a "{{DataError}}" {{DOMException}}.

    1. If |kpk| is not failure, let |key| be |kpk|.

    1. Otherwise (|kpk| is failure):

        1. If |store| does not have a [=key generator=], [=throw=]
            a "{{DataError}}" {{DOMException}}.

        1. Otherwise, if
            [=check that a key could be injected into a value=] with
            |clone| and |store|'s [=object-store/key path=] return
            false, [=throw=] a "{{DataError}}" {{DOMException}}.

1. Return the result (an {{IDBRequest}}) of running
    [=asynchronously execute a request=]
    with |handle| as |source| and
    [=store a record into an object store=] as
    |operation|, using |store|, the |clone| as |value|, |key|, and
    |no-overwrite flag|.

</div>

<div class=algorithm>

The <dfn method for=IDBObjectStore>delete(|query|)</dfn> method, when
invoked, must run these steps:

1. Let |transaction| be **this**'s [=object-store-handle/transaction=].

1. Let |store| be **this**'s [=object-store-handle/object store=].

1. If |store| has been deleted, [=throw=] an
    "{{InvalidStateError}}" {{DOMException}}.

1. If |transaction|'s [=transaction/state=] is not [=transaction/active=],
    then [=throw=] a "{{TransactionInactiveError}}" {{DOMException}}.

1. If |transaction| is a [=read-only transaction=],
    [=throw=] a "{{ReadOnlyError}}" {{DOMException}}.

1. Let |range| be the result of running
    [=convert a value to a key range=] with |query| and
    |null disallowed flag| true. Rethrow any exceptions.

1. Return the result (an {{IDBRequest}}) of running
    [=asynchronously execute a request=]
    with **this** as |source| and
    [=delete records from an object store=] as
    |operation|, using |store| and |range|.

</div>

The |query| parameter may be a [=/key=] or [=key range=] (an {{IDBKeyRange}})
identifying the [=object-store/records=] keys to be
deleted.

<aside class=note>
  Unlike other methods which take keys or key ranges, this method does
  **not** allow null to be given as key. This is to
  reduce the risk that a small bug would clear a whole object store.
</aside>


<div class=algorithm>

The <dfn method for=IDBObjectStore>clear()</dfn> method, when invoked,
must run these steps:

1. Let |transaction| be **this**'s [=object-store-handle/transaction=].

1. Let |store| be **this**'s [=object-store-handle/object store=].

1. If |store| has been deleted, [=throw=] an
    "{{InvalidStateError}}" {{DOMException}}.

1. If |transaction|'s [=transaction/state=] is not [=transaction/active=],
    then [=throw=] a "{{TransactionInactiveError}}" {{DOMException}}.

1. If |transaction| is a [=read-only transaction=],
    [=throw=] a "{{ReadOnlyError}}" {{DOMException}}.

1. Return the result (an {{IDBRequest}}) of running
    [=asynchronously execute a request=]
    with **this** as |source| and
    [=clear an object store=] as
    |operation|, using |store|.


<div class=note>
  The following methods throw a "{{TransactionInactiveError}}" {{DOMException}} if called
  when the [=/transaction=] is not [=transaction/active=].

  <dl class=domintro>
    : |request| = |store| .
          {{IDBObjectStore/get()|get}}(|query|)
    ::
        Retrieves the [=/value=] of the first [=object-store/record=] matching the
        given [=/key=] or [=key range=] in |query|.

        If successful, |request|'s {{IDBRequest/result}} will be the
        [=/value=], or `undefined` if there was no matching
        [=object-store/record=].

    : |request| = |store| .
          {{IDBObjectStore/getKey()|getKey}}(|query|)
    ::
        Retrieves the [=/key=] of the first [=object-store/record=] matching the
        given [=/key=] or [=key range=] in |query|.

        If successful, |request|'s {{IDBRequest/result}} will be the
        [=/key=], or `undefined` if there was no matching
        [=object-store/record=].

    : |request| = |store| .
          {{IDBObjectStore/getAll()|getAll}}(|query| [, |count|])
    ::
        Retrieves the [=/values=] of the [=object-store/records=] matching the
        given [=/key=] or [=key range=] in |query| (up to |count| if given).

        If successful, |request|'s {{IDBRequest/result}} will
        be an [=Array=] of the [=/values=].

    : |request| = |store| .
          {{IDBObjectStore/getAllKeys()|getAllKeys}}(|query| [,
          |count|])
    ::
        Retrieves the [=/keys=] of [=object-store/records=] matching the
        given [=/key=] or [=key range=] in |query| (up to |count| if given).

        If successful, |request|'s {{IDBRequest/result}} will
        be an [=Array=] of the [=/keys=].

    : |request| = |store| .
          {{IDBObjectStore/count()|count}}(|query|)
    ::
        Retrieves the number of [=object-store/records=] matching the
        given [=/key=] or [=key range=] in |query|.

        If successful, |request|'s {{IDBRequest/result}} will be the count.
  </dl>
</div>

The <dfn method for=IDBObjectStore>get(|query|)</dfn> method, when
invoked, must run these steps:

1. Let |transaction| be **this**'s [=object-store-handle/transaction=].

1. Let |store| be **this**'s [=object-store-handle/object store=].

1. If |store| has been deleted, [=throw=] an
    "{{InvalidStateError}}" {{DOMException}}.

1. If |transaction|'s [=transaction/state=] is not [=transaction/active=],
    then [=throw=] a "{{TransactionInactiveError}}" {{DOMException}}.

1. Let |range| be the result of running
    [=convert a value to a key range=] with |query| and
    |null disallowed flag| true. Rethrow any exceptions.

1. Return the result (an {{IDBRequest}}) of running
    [=asynchronously execute a request=]
    with **this** as |source| and [=retrieve a value from
    an object store=] as |operation|, using the
    [=current Realm=] as |targetRealm|,
    |store| and |range|.

</div>

The |query| parameter may be a [=/key=] or [=key range=] (an {{IDBKeyRange}})
identifying the [=object-store/record=] to be retrieved. If a
range is specified, the method retrieves the first existing value in
that range.

<aside class=note>
  This method produces the same result if a record with the given key
  doesn't exist as when a record exists, but has `undefined` as value.
  If you need to tell the two situations apart, you can use
  {{IDBObjectStore/openCursor()}} with the same key. This will return
  a cursor with `undefined` as value if a record exists, or no cursor if
  no such record exists.
</aside>


<div class=algorithm>

The <dfn method for=IDBObjectStore>getKey(|query|)</dfn> method, when
invoked, must run these steps:

1. Let |transaction| be **this**'s [=object-store-handle/transaction=].

1. Let |store| be **this**'s [=object-store-handle/object store=].

1. If |store| has been deleted, [=throw=] an
    "{{InvalidStateError}}" {{DOMException}}.

1. If |transaction|'s [=transaction/state=] is not [=transaction/active=],
    then [=throw=] a "{{TransactionInactiveError}}" {{DOMException}}.

1. Let |range| be the result of running
    [=convert a value to a key range=] with |query| and
    |null disallowed flag| true. Rethrow any exceptions.

1. Return the result (an {{IDBRequest}}) of running
    [=asynchronously execute a request=]
    with **this** as |source| and [=retrieve a key from an
    object store=] as |operation|, using |store|
    and |range|.

</div>

The |query| parameter may be a [=/key=] or [=key range=] (an {{IDBKeyRange}})
identifying the [=object-store/record=] key to be
retrieved. If a range is specified, the method retrieves
the first existing key in that range.


<div class=algorithm>

The <dfn method for=IDBObjectStore>getAll(|query|, |count|)</dfn>
method, when invoked, must run these steps:

1. Let |transaction| be **this**'s [=object-store-handle/transaction=].

1. Let |store| be **this**'s [=object-store-handle/object store=].

1. If |store| has been deleted, [=throw=] an
    "{{InvalidStateError}}" {{DOMException}}.

1. If |transaction|'s [=transaction/state=] is not [=transaction/active=],
    then [=throw=] a "{{TransactionInactiveError}}" {{DOMException}}.

1. Let |range| be the result of running
    [=convert a value to a key range=] with |query|.
    Rethrow any exceptions.

1. Return the result (an {{IDBRequest}}) of running
    [=asynchronously execute a request=]
    with **this** as |source| and
    [=retrieve multiple values from an object store=]
    as |operation|, using the [=current Realm=] as |targetRealm|,
    |store|, |range|, and |count| if given.

</div>

The |query| parameter may be a [=/key=] or [=key range=] (an {{IDBKeyRange}})
identifying the [=object-store/records=] to be retrieved. If null or not given,
an [=unbounded key range=] is used. If |count| is specified and
there are more than |count| records in range, only the first |count|
will be retrieved.


<div class=algorithm>

The <dfn method for=IDBObjectStore>getAllKeys(|query|, |count|)</dfn>
method, when invoked, must run these steps:

1. Let |transaction| be **this**'s [=object-store-handle/transaction=].

1. Let |store| be **this**'s [=object-store-handle/object store=].

1. If |store| has been deleted, [=throw=] an
    "{{InvalidStateError}}" {{DOMException}}.

1. If |transaction|'s [=transaction/state=] is not [=transaction/active=],
    then [=throw=] a "{{TransactionInactiveError}}" {{DOMException}}.

1. Let |range| be the result of running
    [=convert a value to a key range=] with |query|.
    Rethrow any exceptions.

1. Return the result (an {{IDBRequest}}) of running
    [=asynchronously execute a request=]
    with **this** as |source| and
    [=retrieve multiple keys from an object store=] as
    |operation|, using |store|, |range|, and |count| if given.

</div>

The |query| parameter may be a [=/key=] or [=key range=] (an {{IDBKeyRange}})
identifying the [=object-store/records=] keys to be retrieved. If null or not
given, an [=unbounded key range=] is used. If |count| is specified
and there are more than |count| keys in range, only the first |count|
will be retrieved.


<div class=algorithm>

The <dfn method for=IDBObjectStore>count(|query|)</dfn> method, when
invoked, must run these steps:

1. Let |transaction| be **this**'s [=object-store-handle/transaction=].

1. Let |store| be **this**'s [=object-store-handle/object store=].

1. If |store| has been deleted, [=throw=] an
    "{{InvalidStateError}}" {{DOMException}}.

1. If |transaction|'s [=transaction/state=] is not [=transaction/active=],
    then [=throw=] a "{{TransactionInactiveError}}" {{DOMException}}.

1. Let |range| be the result of running
    [=convert a value to a key range=] with |query|.
    Rethrow any exceptions.

1. Return the result (an {{IDBRequest}}) of running
    [=asynchronously execute a request=]
    with **this** as |source| and
    [=count the records in a range=] as |operation|, using
    |source| and |range|.

</div>

The |query| parameter may be a [=/key=] or [=key range=] (an {{IDBKeyRange}})
identifying the [=object-store/records=] keys to be counted. If null or not
given, an [=unbounded key range=] is used.

<div class=note>
  The following methods throw a "{{TransactionInactiveError}}" {{DOMException}} if called
  when the [=/transaction=] is not [=transaction/active=].

  <dl class=domintro>
    : |request| = |store| .
          {{IDBObjectStore/openCursor()|openCursor}}([|query|
              [, |direction| = "next"]])
    ::
        Opens a [=cursor=] over the [=object-store/records=] matching |query|,
        ordered by |direction|. If |query| is null, all [=object-store/records=] in
        |store| are matched.

        If successful, |request|'s {{IDBRequest/result}} will be an
        {{IDBCursorWithValue}} pointing at the first matching
        [=object-store/record=], or null if there were no matching [=object-store/records=].

    : |request| = |store| .
          {{IDBObjectStore/openKeyCursor()|openKeyCursor}}([|query|
              [, |direction| = "next"]])
    ::
        Opens a [=cursor=] with [=cursor/key only flag=] set to true over the
        [=object-store/records=] matching |query|, ordered by |direction|. If
        |query| is null, all [=object-store/records=] in |store| are matched.

        If successful, |request|'s {{IDBRequest/result}} will be an
        {{IDBCursor}} pointing at the first matching [=object-store/record=], or
        null if there were no matching [=object-store/records=].
  </dl>
</div>

<div class=algorithm>

The <dfn method for=IDBObjectStore>openCursor(|query|,
|direction|)</dfn> method, when invoked, must run these steps:

1. Let |transaction| be **this**'s [=object-store-handle/transaction=].

1. Let |store| be **this**'s [=object-store-handle/object store=].

1. If |store| has been deleted, [=throw=] an
    "{{InvalidStateError}}" {{DOMException}}.

1. If |transaction|'s [=transaction/state=] is not [=transaction/active=],
    then [=throw=] a "{{TransactionInactiveError}}" {{DOMException}}.

1. Let |range| be the result of running
    [=convert a value to a key range=] with |query|.
    Rethrow any exceptions.

1. Let |cursor| be a new [=cursor=] with its
    [=cursor/transaction=] set to |transaction|,
    undefined [=cursor/position=],
    [=cursor/direction=] set to |direction|,
    [=cursor/got value flag=] set to false,
    undefined [=cursor/key=] and [=cursor/value=],
    [=cursor/source=] set to |store|,
    [=cursor/range=] set to |range|, and
    [=cursor/key only flag=] set to false.

1. Let |request| be the result of running
    [=asynchronously execute a request=] with **this** as |source| and [=iterate a cursor=] as
    |operation|, using the [=current Realm=] as |targetRealm|, and
    |cursor|.

1. Set |cursor|'s [=cursor/request=] to |request|.

1. Return |request|.

</div>

The |query| parameter may be a [=/key=] or [=key range=] (an {{IDBKeyRange}})
to use as the [=cursor=]'s [=cursor/range=].
If null or not given, an [=unbounded key range=] is used.


<div class=algorithm>

The <dfn method for=IDBObjectStore>openKeyCursor(|query|,
|direction|)</dfn> method, when invoked, must run these steps:

1. Let |transaction| be **this**'s [=object-store-handle/transaction=].

1. Let |store| be **this**'s [=object-store-handle/object store=].

1. If |store| has been deleted, [=throw=] an
    "{{InvalidStateError}}" {{DOMException}}.

1. If |transaction|'s [=transaction/state=] is not [=transaction/active=],
    then [=throw=] a "{{TransactionInactiveError}}" {{DOMException}}.

1. Let |range| be the result of running
    [=convert a value to a key range=] with |query|.
    Rethrow any exceptions.

1. Let |cursor| be a new [=cursor=] with its
    [=cursor/transaction=] set to |transaction|,
    undefined [=cursor/position=],
    [=cursor/direction=] set to |direction|,
    [=cursor/got value flag=] set to false,
    undefined [=cursor/key=] and [=cursor/value=],
    [=cursor/source=] set to |store|,
    [=cursor/range=] set to |range|, and
    [=cursor/key only flag=] set to true.

1. Let |request| be the result of running
    [=asynchronously execute a request=] with **this** as |source| and [=iterate a cursor=] as
    |operation|, using the [=current Realm=] as |targetRealm|, and
    |cursor|.

1. Set |cursor|'s [=cursor/request=] to |request|.

1. Return |request|.

</div>

The |query| parameter may be a [=/key=] or [=key range=] (an {{IDBKeyRange}})
to use as the [=cursor=]'s [=cursor/range=]. If null
or not given, an [=unbounded key range=] is used.

<dl class="domintro note">
    : |index| = |store| . index(|name|)
    ::
        Returns an {{IDBIndex}} for the [=/index=] named |name| in |store|.

    : |index| = |store| .
          {{IDBObjectStore/createIndex()|createIndex}}(|name|,
              |keyPath| [, |options|])
    ::
        Creates a new [=/index=] in |store| with the given |name|,
        |keyPath| and |options| and returns a new {{IDBIndex}}. If the
        |keyPath| and |options| define constraints that cannot be
        satisfied with the data already in |store| the [=/upgrade
        transaction=] will [=transaction/abort=] with
        a "{{ConstraintError}}" {{DOMException}}.

        Throws an "{{InvalidStateError}}" {{DOMException}} if not called within an [=/upgrade
        transaction=].

    : |store| . {{IDBObjectStore/deleteIndex()|deleteIndex}}(|name|)
    ::
        Deletes the [=/index=] in |store| with the given |name|.

        Throws an "{{InvalidStateError}}" {{DOMException}} if not called within an [=/upgrade
        transaction=].
</dl>

<div class=algorithm>

The <dfn method for=IDBObjectStore>createIndex(|name|, |keyPath|,
|options|)</dfn> method, when invoked, must run these steps:

1. Let |transaction| be **this**'s [=object-store-handle/transaction=].

1. Let |store| be **this**'s [=object-store-handle/object store=].

1. If |transaction| is not an [=/upgrade transaction=],
    [=throw=] an "{{InvalidStateError}}" {{DOMException}}.

1. If |store| has been deleted, [=throw=] an
    "{{InvalidStateError}}" {{DOMException}}.

1. If |transaction|'s [=transaction/state=] is not [=transaction/active=],
    then [=throw=] a "{{TransactionInactiveError}}" {{DOMException}}.

1. If an [=/index=] [=index/named=]
    |name| already exists in |store|, [=throw=] a
    "{{ConstraintError}}" {{DOMException}}.

1. If |keyPath| is not a [=valid key path=], [=throw=]
    a "{{SyntaxError}}" {{DOMException}}.

1. Let |unique| be |options|'s
    {{IDBIndexParameters/unique}} member.

1. Let |multiEntry| be |options|'s
    {{IDBIndexParameters/multiEntry}} member.

1. If |keyPath| is a sequence and |multiEntry| is
    true, [=throw=] an "{{InvalidAccessError}}" {{DOMException}}.

1. Let |index| be a new [=/index=] in |store|.
    Set |index|'s [=index/name=] to |name|, [=index/key path=] to
    |keyPath|,
    [=unique flag=] to |unique|, and
    [=multiEntry flag=] to |multiEntry|.

1. Add |index| to **this**'s [=index set=].

1. Return a new [=index handle=] associated with |index| and **this**.

</div>

This method creates and returns a new [=/index=] with the
given name in the [=/object store=]. Note that this method
must only be called from within an [=/upgrade transaction=].

The index that is requested to be created can contain constraints on
the data allowed in the index's [=referenced=] object store, such
as requiring uniqueness of the values referenced by the index's
[=index/key path=]. If the [=referenced=] object store already contains data
which violates these constraints, this must not cause the
implementation of {{IDBObjectStore/createIndex()}} to throw an
exception or affect what it returns. The implementation must still
create and return an {{IDBIndex}} object, and the implementation must
[=queue a task=] to abort the [=/upgrade transaction=] which was
used for the {{IDBObjectStore/createIndex()}} call.

This method synchronously modifies the {{IDBObjectStore/indexNames}}
property on the {{IDBObjectStore}} instance on which it was called.
Although this method does not return an {{IDBRequest}} object, the
index creation itself is processed as an asynchronous request within
the [=/upgrade transaction=].

In some implementations it is possible for the implementation to
asynchronously run into problems creating the index after the
createIndex method has returned. For example in implementations where
metadata about the newly created index is queued up to be inserted
into the database asynchronously, or where the implementation might
need to ask the user for permission for quota reasons. Such
implementations must still create and return an {{IDBIndex}} object,
and once the implementation determines that creating the index has
failed, it must run the steps to [=abort
a transaction=] using an appropriate error as |error|. For example
if creating the [=/index=] failed due to quota reasons,
a "{{QuotaExceededError}}" {{DOMException}} must be used as error and if the index can't be
created due to [=unique flag=] constraints, a "{{ConstraintError}}" {{DOMException}}
must be used as error.

<aside class=example id=example-async-index-creation>

  The asynchronous creation of indexes is observable in the following example:

```js
    const request1 = objectStore.put({name: "betty"}, 1);
    const request2 = objectStore.put({name: "betty"}, 2);
    const index = objectStore.createIndex("by_name", "name", {unique: true});
```

  At the point where {{createIndex()}} called, neither of the
  [=/requests=] have executed. When the second request executes, a
  duplicate name is created. Since the index creation is considered an
  asynchronous [=/request=], the index's <a data-lt="unique
  flag">uniqueness constraint</a> does not cause the second
  [=/request=] to fail. Instead, the [=/transaction=] will
  be [=transaction/aborted=] when the index is created and the constraint
  fails.
</aside>


<div class=algorithm>

The <dfn method for=IDBObjectStore>index(|name|)</dfn> method, when
invoked, must run these steps:

1. Let |transaction| be **this**'s [=object-store-handle/transaction=].

1. Let |store| be **this**'s [=object-store-handle/object store=].

1. If |store| has been deleted, [=throw=] an
    "{{InvalidStateError}}" {{DOMException}}.

1. If |transaction|'s [=transaction/state=] is [=transaction/finished=],
    then [=throw=] an "{{InvalidStateError}}" {{DOMException}}.

1. Let |index| be the [=/index=]
    [=index/named=] |name| in **this**'s
    [=index set=] if one exists, or [=throw=]
    a "{{NotFoundError}}" {{DOMException}} otherwise.

1. Return an [=index handle=] associated with |index| and **this**.

</div>

<aside class=note>
  Each call to this method on the same {{IDBObjectStore}} instance
  with the same name returns the same {{IDBIndex}} instance.
</aside>

<aside class=note>
  The returned {{IDBIndex}} instance is specific to this
  {{IDBObjectStore}} instance. If this method is called on a
  different {{IDBObjectStore}} instance with the same name, a
  different {{IDBIndex}} instance is returned.
</aside>


<div class=algorithm>

The <dfn method for=IDBObjectStore>deleteIndex(|name|)</dfn> method,
when invoked, must run these steps:

1. Let |transaction| be **this**'s [=object-store-handle/transaction=].

1. Let |store| be **this**'s [=object-store-handle/object store=].

1. If |transaction| is not an [=/upgrade transaction=],
    [=throw=] an "{{InvalidStateError}}" {{DOMException}}.

1. If |store| has been deleted, [=throw=] an
    "{{InvalidStateError}}" {{DOMException}}.

1. If |transaction|'s [=transaction/state=] is not [=transaction/active=],
    then [=throw=] a "{{TransactionInactiveError}}" {{DOMException}}.

1. Let |index| be the [=/index=] [=index/named=] |name|
    in |store| if one exists, or [=throw=] a "{{NotFoundError}}" {{DOMException}}
    otherwise.

1. Remove |index| from **this**'s [=index set=].

1. Destroy |index|.

</div>

This method destroys the [=/index=] with the given name in the
[=/object store=]. Note that this method must only be called from
within an [=/upgrade transaction=].

This method synchronously modifies the {{IDBObjectStore/indexNames}}
property on the {{IDBObjectStore}} instance on which it was called.
Although this method does not return an {{IDBRequest}} object, the
index destruction itself is processed as an asynchronous request
within the [=/upgrade transaction=].


<!-- ============================================================ -->
## The {{IDBIndex}} interface ## {#index-interface}
<!-- ============================================================ -->

The {{IDBIndex}} interface represents an [=index handle=].


<xmp class=idl>
[Exposed=(Window,Worker)]
interface IDBIndex {
  attribute DOMString name;
  [SameObject] readonly attribute IDBObjectStore objectStore;
  readonly attribute any keyPath;
  readonly attribute boolean multiEntry;
  readonly attribute boolean unique;

  [NewObject] IDBRequest get(any query);
  [NewObject] IDBRequest getKey(any query);
  [NewObject] IDBRequest getAll(optional any query,
                                optional [EnforceRange] unsigned long count);
  [NewObject] IDBRequest getAllKeys(optional any query,
                                    optional [EnforceRange] unsigned long count);
  [NewObject] IDBRequest count(optional any query);

  [NewObject] IDBRequest openCursor(optional any query,
                                    optional IDBCursorDirection direction = "next");
  [NewObject] IDBRequest openKeyCursor(optional any query,
                                       optional IDBCursorDirection direction = "next");
};
</xmp>

<dl class="domintro note">
    : |index| . {{IDBIndex/name}}
    :: Returns the [=index/name=] of the index.

    : |index| . {{IDBIndex/name}} = |newName|
    :: Updates the [=index/name=] of the store to |newName|.

       Throws an "{{InvalidStateError}}" {{DOMException}} if not called within an [=/upgrade
       transaction=].

    : |index| . {{IDBIndex/objectStore}}
    :: Returns the {{IDBObjectStore}} the index belongs to.

    : |index| . keyPath
    :: Returns the [=/key path=] of the index.

    : |index| . multiEntry
    :: Returns true if the index's [=index/multiEntry flag=] is true.

    : |index| . unique
    :: Returns true if the index's [=index/unique flag=] is true.
</dl>

The <dfn attribute for=IDBIndex>name</dfn> attribute's getter must
return **this**'s [=index/name=].

<details class=note>
  <summary>
    Is this the same as the [=/index=]'s [=index/name=]?
  </summary>
  As long as the [=/transaction=] has not [=transaction/finished=],
  this is the same as the associated [=/index=]'s
  [=index/name=]. But once the [=/transaction=] has
  [=transaction/finished=], this attribute will not reflect changes made with a
  later [=/upgrade transaction=].
</details>


<div class=algorithm>

The {{IDBIndex/name}} attribute's setter must run these steps:

1. Let |name| be the given value.

1. Let |transaction| be **this**'s [=index-handle/transaction=].

1. Let |index| be **this**'s [=index-handle/index=].

1. If |transaction| is not an [=/upgrade transaction=],
    [=throw=] an "{{InvalidStateError}}" {{DOMException}}.

1. If |transaction|'s [=transaction/state=] is not [=transaction/active=],
    then [=throw=] a "{{TransactionInactiveError}}" {{DOMException}}.

1. If |index| or |index|'s [=/object store=] has
    been deleted, [=throw=] an "{{InvalidStateError}}" {{DOMException}}.

1. If |index|'s [=index/name=] is equal to
    |name|, terminate these steps.

1. If an [=/index=] [=index/named=]
    |name| already exists in |index|'s [=/object
    store=], [=throw=] a "{{ConstraintError}}" {{DOMException}}.

1. Set |index|'s [=index/name=] to
    |name|.

1. Set **this**'s [=index-handle/name=] to |name|.

</div>


The <dfn attribute for=IDBIndex>objectStore</dfn> attribute's getter
must return **this**'s [=index-handle/object store handle=].

The <dfn attribute for=IDBIndex>keyPath</dfn> attribute's getter must
return **this**'s [=index-handle/index=]'s
[=object-store/key path=]. The [=/key path=] is converted as a
{{DOMString}} (if a string) or a [=sequence&lt;DOMString&gt;=] (if a
list of strings), per [[!WEBIDL]].

The returned value is not the same instance that was used when the
[=/index=] was created. However, if this attribute returns an
object (specifically an [=Array=]), it returns the same object
instance every time it is inspected. Changing the properties of the
object has no effect on the [=/index=].

The <dfn attribute for=IDBIndex>multiEntry</dfn> attribute's getter
must return **this**'s [=index-handle/index=]'s [=multiEntry flag=].

The <dfn attribute for=IDBIndex>unique</dfn> attribute's getter must
return **this**'s [=index-handle/index=]'s [=unique flag=].


<div class=note>
  The following methods throw an "{{TransactionInactiveError}}" {{DOMException}} if called
  when the [=/transaction=] is not [=transaction/active=].

  <dl class=domintro>
    : |request| = |index| .
          {{IDBIndex/get()|get}}(|query|)
    ::
        Retrieves the [=/value=] of the first [=object-store/record=] matching the
        given [=/key=] or [=key range=] in |query|.

        If successful, |request|'s {{IDBRequest/result}} will be the
        [=/value=], or `undefined` if there was no matching
        [=object-store/record=].

    : |request| = |index| .
          {{IDBIndex/getKey()|getKey}}(|query|)
    ::
        Retrieves the [=/key=] of the first [=object-store/record=] matching the
        given [=/key=] or [=key range=] in |query|.

        If successful, |request|'s {{IDBRequest/result}} will be the
        [=/key=], or `undefined` if there was no matching
        [=object-store/record=].

    : |request| = |index| .
          {{IDBIndex/getAll()|getAll}}(|query| [, |count|])
    ::
        Retrieves the [=/values=] of the [=object-store/records=] matching the given
        [=/key=] or [=key range=] in |query| (up to |count| if given).

        If successful, |request|'s {{IDBRequest/result}} will be an
        [=Array=] of the [=/values=].

    : |request| = |index| .
          {{IDBIndex/getAllKeys()|getAllKeys}}(|query| [,
          |count|])
    ::
        Retrieves the [=/keys=] of [=object-store/records=] matching the given
        [=/key=] or [=key range=] in |query| (up to |count| if given).

        If successful, |request|'s {{IDBRequest/result}} will be an
        [=Array=] of the [=/keys=].

    : |request| = |index| .
          {{IDBIndex/count()|count}}(|query|)
    ::
        Retrieves the number of [=object-store/records=] matching the given [=/key=]
        or [=key range=] in |query|.

        If successful, |request|'s {{IDBRequest/result}} will be the
        count.
  </dl>
</div>

<div class=algorithm>

The <dfn method for=IDBIndex>get(|query|)</dfn> method, when invoked,
must run these steps:

1. Let |transaction| be **this**'s [=index-handle/transaction=].

1. Let |index| be **this**'s [=index-handle/index=].

1. If |index| or |index|'s [=/object store=] has
    been deleted, [=throw=] an "{{InvalidStateError}}" {{DOMException}}.

1. If |transaction|'s [=transaction/state=] is not [=transaction/active=],
    then [=throw=] a "{{TransactionInactiveError}}" {{DOMException}}.

1. Let |range| be the result of running
    [=convert a value to a key range=] with |query| and
    |null disallowed flag| true. Rethrow any exceptions.

1. Return the result (an {{IDBRequest}}) of running
    [=asynchronously execute a request=]
    with **this** as |source| and
    [=retrieve a referenced value from an index=]
    as |operation|, using the [=current Realm=] as |targetRealm|,
    |index| and |range|.

</div>

The |query| parameter may be a [=/key=] or [=key range=] (an {{IDBKeyRange}})
identifying the [=object-store/record=] to be retrieved. If a
range is specified, the method retrieves the first existing record in
that range.


<aside class=note>
  This method produces the same result if a record with the given key
  doesn't exist as when a record exists, but has `undefined` as value.
  If you need to tell the two situations apart, you can use
  {{IDBIndex/openCursor()}} with the same key. This will return a
  cursor with `undefined` as value if a record exists, or no cursor if
  no such record exists.
</aside>


<div class=algorithm>

The <dfn method for=IDBIndex>getKey(|query|)</dfn> method, when
invoked, must run these steps:

1. Let |transaction| be **this**'s [=index-handle/transaction=].

1. Let |index| be **this**'s [=index-handle/index=].

1. If |index| or |index|'s [=/object store=] has been deleted,
    [=throw=] an "{{InvalidStateError}}" {{DOMException}}.

1. If |transaction|'s [=transaction/state=] is not [=transaction/active=],
    then [=throw=] a "{{TransactionInactiveError}}" {{DOMException}}.

1. Let |range| be the result of running [=convert a
    value to a key range=] with |query| and |null disallowed flag|
    true. Rethrow any exceptions.

1. Return the result (an {{IDBRequest}}) of running
    [=asynchronously execute a request=]
    with **this** as |source| and
    [=retrieve a value from an index=] as |operation|, using |index|
    and |range|.

</div>

The |query| parameter may be a [=/key=] or [=key range=] (an {{IDBKeyRange}})
identifying the [=object-store/record=] key to be retrieved.
If a range is specified, the method retrieves the first existing key
in that range.


<div class=algorithm>

The <dfn method for=IDBIndex>getAll(|query|, |count|)</dfn> method,
when invoked, must run these steps:

1. Let |transaction| be **this**'s [=index-handle/transaction=].

1. Let |index| be **this**'s [=index-handle/index=].

1. If |index| or |index|'s [=/object store=] has
    been deleted, [=throw=] an "{{InvalidStateError}}" {{DOMException}}.

1. If |transaction|'s [=transaction/state=] is not [=transaction/active=],
    then [=throw=] a "{{TransactionInactiveError}}" {{DOMException}}.

1. Let |range| be the result of running
    [=convert a value to a key range=] with |query|.
    Rethrow any exceptions.

1. Return the result (an {{IDBRequest}}) of running
    [=asynchronously execute a request=]
    with **this** as |source| and
    [=retrieve multiple referenced values from an index=] as
    |operation|, using the [=current Realm=] as |targetRealm|,
    |index|, |range|, and |count| if given.

</div>

The |query| parameter may be a [=/key=] or [=key range=] (an {{IDBKeyRange}})
identifying the [=object-store/records=] to be retrieved. If null or not given,
an [=unbounded key range=] is used. If |count| is specified and
there are more than |count| records in range, only the first |count|
will be retrieved.


<div class=algorithm>

The <dfn method for=IDBIndex>getAllKeys(|query|, |count|)</dfn>
method, when invoked, must run these steps:

1. Let |transaction| be **this**'s [=index-handle/transaction=].

1. Let |index| be **this**'s [=index-handle/index=].

1. If |index| or |index|'s [=/object store=] has
    been deleted, [=throw=] an "{{InvalidStateError}}" {{DOMException}}.

1. If |transaction|'s [=transaction/state=] is not [=transaction/active=],
    then [=throw=] a "{{TransactionInactiveError}}" {{DOMException}}.

1. Let |range| be the result of running
    [=convert a value to a key range=] with |query|.
    Rethrow any exceptions.

1. Return the result (an {{IDBRequest}}) of running
    [=asynchronously execute a request=]
    with **this** as |source| and
    [=retrieve multiple values from an index=] as |operation|, using
    |index|, |range|, and |count| if given.

</div>

The |query| parameter may be a [=/key=] or [=key range=] (an {{IDBKeyRange}})
identifying the [=object-store/records=] keys to be retrieved. If null or not
given, an [=unbounded key range=] is used. If |count| is specified
and there are more than |count| keys in range, only the first |count|
will be retrieved.


<div class=algorithm>

The <dfn method for=IDBIndex>count(|query|)</dfn> method, when
invoked, must run these steps:

1. Let |transaction| be **this**'s [=index-handle/transaction=].

1. Let |index| be **this**'s [=index-handle/index=].

1. If |index| or |index|'s [=/object store=] has
    been deleted, [=throw=] an "{{InvalidStateError}}" {{DOMException}}.

1. If |transaction|'s [=transaction/state=] is not [=transaction/active=],
    then [=throw=] a "{{TransactionInactiveError}}" {{DOMException}}.

1. Let |range| be the result of running
    [=convert a value to a key range=] with |query|.
    Rethrow any exceptions.

1. Return the result (an {{IDBRequest}}) of running
    [=asynchronously execute a request=]
    with **this** as |source| and
    [=count the records in a range=] as |operation|, using
    [=/index=] as |source| and |range|.

</div>

The |query| parameter may be a [=/key=] or [=key range=] (an {{IDBKeyRange}})
identifying the [=object-store/records=] keys to be counted. If null or not
given, an [=unbounded key range=] is used.

<div class=note>
  The following methods throw an "{{TransactionInactiveError}}" {{DOMException}} if called
  when the [=/transaction=] is not [=transaction/active=].

  <dl class=domintro>
    : |request| = |index| .
          {{IDBIndex/openCursor()|openCursor}}([|query|
              [, |direction| = "next"]])
    ::
        Opens a [=cursor=] over the [=object-store/records=] matching |query|,
        ordered by |direction|. If |query| is null, all [=object-store/records=] in
        |index| are matched.

        If successful, |request|'s {{IDBRequest/result}} will be an
        {{IDBCursorWithValue}}, or null if there were no matching
        [=object-store/records=].

    : |request| = |index| .
          {{IDBIndex/openKeyCursor()|openKeyCursor}}([|query|
              [, |direction| = "next"]])
    ::
        Opens a [=cursor=] with [=cursor/key only flag=] set to true over the
        [=object-store/records=] matching |query|, ordered by |direction|. If
        |query| is null, all [=object-store/records=] in |index| are matched.

        If successful, |request|'s {{IDBRequest/result}} will be an
        {{IDBCursor}}, or null if there were no matching [=object-store/records=].
  </dl>
</div>

<div class=algorithm>

The <dfn method for=IDBIndex>openCursor(|query|, |direction|)</dfn>
method, when invoked, must run these steps:

1. Let |transaction| be **this**'s [=index-handle/transaction=].

1. Let |index| be **this**'s [=index-handle/index=].

1. If |index| or |index|'s [=/object store=] has been deleted,
    [=throw=] an "{{InvalidStateError}}" {{DOMException}}.

1. If |transaction|'s [=transaction/state=] is not [=transaction/active=],
    then [=throw=] a "{{TransactionInactiveError}}" {{DOMException}}.

1. Let |range| be the result of running
    [=convert a value to a key range=] with |query|.
    Rethrow any exceptions.

1. Let |cursor| be a new [=cursor=] with its
    [=cursor/transaction=] set to |transaction|,
    undefined [=cursor/position=],
    [=cursor/direction=] set to |direction|,
    [=cursor/got value flag=] set to false,
    undefined [=cursor/key=] and [=cursor/value=],
    [=cursor/source=] set to |index|,
    [=cursor/range=] set to |range|, and
    [=cursor/key only flag=] set to false.

1. Let |request| be the result of running
    [=asynchronously execute a request=] with **this** as
    |source| and [=iterate a cursor=] as |operation|,
    using the [=current Realm=] as |targetRealm|, and |cursor|.

1. Set |cursor|'s [=cursor/request=] to |request|.

1. Return |request|.

</div>

The |query| parameter may be a [=/key=] or [=key range=] (an {{IDBKeyRange}})
to use as the [=cursor=]'s [=cursor/range=]. If null
or not given, an [=unbounded key range=] is used.


<div class=algorithm>

The <dfn method for=IDBIndex>openKeyCursor(|query|, |direction|)</dfn>
method, when invoked, must run these steps:

1. Let |transaction| be **this**'s [=index-handle/transaction=].

1. Let |index| be **this**'s [=index-handle/index=].

1. If |index| or |index|'s [=/object store=] has
    been deleted, [=throw=] an "{{InvalidStateError}}" {{DOMException}}.

1. If |transaction|'s [=transaction/state=] is not [=transaction/active=],
    then [=throw=] a "{{TransactionInactiveError}}" {{DOMException}}.

1. Let |range| be the result of running
    [=convert a value to a key range=] with |query|.
    Rethrow any exceptions.

1. Let |cursor| be a new [=cursor=] with its
    [=cursor/transaction=] set to |transaction|,
    undefined [=cursor/position=],
    [=cursor/direction=] set to |direction|,
    [=cursor/got value flag=] set to false,
    undefined [=cursor/key=] and [=cursor/value=],
    [=cursor/source=] set to |index|,
    [=cursor/range=] set to |range|, and
    [=cursor/key only flag=] set to true.

1. Let |request| be the result of running
    [=asynchronously execute a request=] with **this** as
    |source| and [=iterate a cursor=] as |operation|,
    using the [=current Realm=] as |targetRealm|, and |cursor|.

1. Set |cursor|'s [=cursor/request=] to |request|.

1. Return |request|.

</div>

The |query| parameter may be a [=/key=] or [=key range=] (an {{IDBKeyRange}})
to use as the [=cursor=]'s [=cursor/range=]. If null
or not given, an [=unbounded key range=] is used.


<!-- ============================================================ -->
## The {{IDBKeyRange}} interface ## {#keyrange}
<!-- ============================================================ -->

The {{IDBKeyRange}} interface represents a
[=key range=].

<xmp class=idl>
[Exposed=(Window,Worker)]
interface IDBKeyRange {
  readonly attribute any lower;
  readonly attribute any upper;
  readonly attribute boolean lowerOpen;
  readonly attribute boolean upperOpen;

  // Static construction methods:
  [NewObject] static IDBKeyRange only(any value);
  [NewObject] static IDBKeyRange lowerBound(any lower, optional boolean open = false);
  [NewObject] static IDBKeyRange upperBound(any upper, optional boolean open = false);
  [NewObject] static IDBKeyRange bound(any lower,
                                       any upper,
                                       optional boolean lowerOpen = false,
                                       optional boolean upperOpen = false);

  boolean includes(any key);
};
</xmp>

<dl class="domintro note">
    : |range| . {{IDBKeyRange/lower}}
    :: Returns the range's [=lower bound=], or `undefined` if none.

    : |range| . {{IDBKeyRange/upper}}
    :: Returns the range's [=upper bound=], or `undefined` if none.

    : |range| . {{IDBKeyRange/lowerOpen}}
    :: Returns the range's [=lower open flag=].

    : |range| . {{IDBKeyRange/upperOpen}}
    :: Returns the range's [=upper open flag=].
</dl>

The <dfn attribute for=IDBKeyRange>lower</dfn> attribute's getter must
return result of running [=convert a key to a value=]
with **this**'s [=lower bound=] if it is not null, or undefined otherwise.

The <dfn attribute for=IDBKeyRange>upper</dfn> attribute's getter must
return the result of running [=convert a key to a
value=] with **this**'s [=upper bound=] if it is not null, or undefined
otherwise.

The <dfn attribute for=IDBKeyRange>lowerOpen</dfn> attribute's getter
must return **this**'s [=lower open flag=].

The <dfn attribute for=IDBKeyRange>upperOpen</dfn> attribute's getter
must return **this**'s [=upper open flag=].

<dl class="domintro note">
    : |range| = {{IDBKeyRange}} .
        {{IDBKeyRange/only()|only}}(|key|)
    ::
        Returns a new {{IDBKeyRange}} spanning only |key|.

    : |range| = {{IDBKeyRange}} .
        {{IDBKeyRange/lowerBound()|lowerBound}}(|key| [, |open| = false])
    ::
        Returns a new {{IDBKeyRange}} starting at |key| with no
        upper bound. If |open| is true, |key| is not included in the
        range.

    : |range| = {{IDBKeyRange}} .
        {{IDBKeyRange/upperBound()|upperBound}}(|key| [, |open| = false])
    ::
        Returns a new {{IDBKeyRange}} with no lower bound and ending at
        |key|. If |open| is true, |key| is not included in the range.

    : |range| = {{IDBKeyRange}} .
        {{IDBKeyRange/bound()|bound}}(|lower|, |upper|
            [, |lowerOpen| = false
            [, |upperOpen| = false]])
    ::
        Returns a new {{IDBKeyRange}} spanning from |lower| to |upper|.
        If |lowerOpen| is true, |lower| is not included in the range.
        If |upperOpen| is true, |upper| is not included in the range.
</dl>

<div class=algorithm>

The <dfn method for=IDBKeyRange>only(|value|)</dfn> method, when
invoked, must run these steps:

1. Let |key| be the result of running [=convert
    a value to a key=] with |value|. Rethrow any exceptions.

1. If |key| is invalid, [=throw=] a "{{DataError}}" {{DOMException}}.

1. Create and return a new [=key range=] [=containing only=]
    |key|.

</div>

<div class=algorithm>

The <dfn method for=IDBKeyRange>lowerBound(|lower|, |open|)</dfn>
method, when invoked, must run these steps:

1. Let |lowerKey| be the result of running [=convert a
    value to a key=] with |lower|. Rethrow any exceptions.

1. If |lowerKey| is invalid, [=throw=] a "{{DataError}}" {{DOMException}}.

1. Create and return a new [=key range=] with [=lower bound=]
    set to |lowerKey|, [=lower open flag=] set to |open|,
    [=upper bound=] set to null, and [=upper open flag=]
    set to true.

</div>

<div class=algorithm>

The <dfn method for=IDBKeyRange>upperBound(|upper|, |open|)</dfn>
method, when invoked, must run these steps:

1. Let |upperKey| be the result of running [=convert a
    value to a key=] with |upper|. Rethrow any exceptions.

1. If |upperKey| is invalid, [=throw=] a "{{DataError}}" {{DOMException}}.

1. Create and return a new [=key range=] with [=lower bound=]
    set to null, [=lower open flag=] set to true, [=upper bound=] set to
    |upperKey|, and [=upper open flag=] set to |open|.

</div>

<div class=algorithm>

The <dfn method for=IDBKeyRange>bound(|lower|, |upper|, |lowerOpen|,
|upperOpen|)</dfn> method, when invoked, must run these steps:

1. Let |lowerKey| be the result of running [=convert a
    value to a key=] with |lower|. Rethrow any exceptions.

1. If |lowerKey| is invalid, [=throw=] a "{{DataError}}" {{DOMException}}.

1. Let |upperKey| be the result of running [=convert a
    value to a key=] with |upper|. Rethrow any exceptions.

1. If |upperKey| is invalid, [=throw=] a "{{DataError}}" {{DOMException}}.

1. If |lowerKey| is [=greater than=] |upperKey|, [=throw=] a
    "{{DataError}}" {{DOMException}}.

1. Create and return a new [=key range=] with [=lower bound=]
    set to |lowerKey|, [=lower open flag=] set to |lowerOpen|,
    [=upper bound=] set to |upperKey| and [=upper open
    flag=] set to |upperOpen|.

</div>

<dl class="domintro note">
    : |range| .
        {{IDBKeyRange/includes()|includes}}(|key|)
    :: Returns true if |key| is included in the range, and false otherwise.
</dl>

<div class=algorithm>

The <dfn method for=IDBKeyRange>includes(|key|)</dfn> method, when
invoked, must run these steps:

1. Let |k| be the result of running [=convert a
    value to a key=] with |key|. Rethrow any exceptions.

1. If |k| is invalid, [=throw=] a "{{DataError}}" {{DOMException}}.

1. Return true if |k| is [=in=]
    this range, and false otherwise.

</div>


<!-- ============================================================ -->
## The {{IDBCursor}} interface ## {#cursor-interface}
<!-- ============================================================ -->

[=Cursor=] objects implement the {{IDBCursor}} interface. There
is only ever one {{IDBCursor}} instance representing a given
[=cursor=]. There is no limit on how many cursors can be used at
the same time.


<xmp class=idl>
[Exposed=(Window,Worker)]
interface IDBCursor {
  readonly attribute (IDBObjectStore or IDBIndex) source;
  readonly attribute IDBCursorDirection direction;
  readonly attribute any key;
  readonly attribute any primaryKey;
  [SameObject] readonly attribute IDBRequest request;

  void advance([EnforceRange] unsigned long count);
  void continue(optional any key);
  void continuePrimaryKey(any key, any primaryKey);

  [NewObject] IDBRequest update(any value);
  [NewObject] IDBRequest delete();
};

enum IDBCursorDirection {
  "next",
  "nextunique",
  "prev",
  "prevunique"
};
</xmp>

<dl class="domintro note">
    : |cursor| . {{IDBCursor/source}}
    ::
        Returns the {{IDBObjectStore}} or {{IDBIndex}} the cursor was opened from.

    : |cursor| . {{IDBCursor/direction}}
    ::
        Returns the [=cursor/direction=]
        ({{"next"}}, {{"nextunique"}}, {{"prev"}} or {{"prevunique"}})
        of the cursor.

    : |cursor| . {{IDBCursor/key}}
    ::
        Returns the [=cursor/key=] of the cursor.
        Throws a "{{InvalidStateError}}" {{DOMException}} if the cursor is advancing or is finished.

    : |cursor| . {{IDBCursor/primaryKey}}
    ::
        Returns the [=cursor/effective key=] of the cursor.
        Throws a "{{InvalidStateError}}" {{DOMException}} if the cursor is advancing or is finished.

    : |cursor| . {{IDBCursor/request}}
    ::
        Returns the [=cursor/request=] that was used to obtain this cursor.
</dl>


The <dfn attribute for=IDBCursor>source</dfn> attribute's getter must
return **this**'s [=cursor/source=]. This
attribute never returns null or throws an exception, even if the
cursor is currently being iterated, has iterated past its end, or its
[=/transaction=] is not [=transaction/active=].

The <dfn attribute for=IDBCursor>direction</dfn> attribute's getter
must return **this**'s [=cursor/direction=].

The <dfn attribute for=IDBCursor>key</dfn> attribute's getter must
return the result of running [=convert a key to a
value=] with the cursor's current [=cursor/key=]. Note that
if this property returns an object (e.g. a [=Date=] or
[=Array=]), it returns the same object instance every time it is
inspected, until the cursor's [=cursor/key=] is changed. This
means that if the object is modified, those modifications will be seen
by anyone inspecting the value of the cursor. However modifying such
an object does not modify the contents of the database.

The <dfn attribute for=IDBCursor>primaryKey</dfn> attribute's getter
must return the result of running [=convert a key to a
value=] with the cursor's current [=effective key=]. Note that if
this property returns an object (e.g. a [=Date=] or [=Array=]),
it returns the same object instance every time it is inspected, until
the cursor's [=effective key=] is changed. This means that if the
object is modified, those modifications will be seen by anyone
inspecting the value of the cursor. However modifying such an object
does not modify the contents of the database.

The <dfn attribute for=IDBCursor>request</dfn> attribute's getter must
return **this**'s [=cursor/request=].

<aside class=advisement>
  &#x1F6A7;
  The {{IDBCursor/request}} attribute is new in this edition.
  &#x1F6A7;
</aside>

<div class=note>
  The following methods advance a [=cursor=]. Once the cursor has
  advanced, a <a event>`success`</a> event will be fired at the
  same {{IDBRequest}} returned when the cursor was opened. The
  {{IDBRequest/result}} will be the same cursor if a [=object-store/record=] was
  in range, or `undefined` otherwise.

  If called while the cursor is already advancing, an "{{InvalidStateError}}" {{DOMException}}
  will be thrown.

  The following methods throw a "{{TransactionInactiveError}}" {{DOMException}} if called
  when the [=/transaction=] is not [=transaction/active=].

  <dl class=domintro>
    : |cursor| . {{IDBCursor/advance()|advance}}(|count|)
    ::
        Advances the cursor through the next |count| [=object-store/records=] in
        range.

    : |cursor| . {{IDBCursor/continue()|continue}}()
    ::
        Advances the cursor to the next [=object-store/record=] in range.

    : |cursor| . {{IDBCursor/continue()|continue}}(|key|)
    ::
        Advances the cursor to the next [=object-store/record=] in range matching or
        after |key|.

    : |cursor| .
        {{IDBCursor/continuePrimaryKey()|continuePrimaryKey}}(|key|,
        |primaryKey|)
    ::
        Advances the cursor to the next [=object-store/record=] in range matching
        or after |key| and |primaryKey|. Throws an "{{InvalidAccessError}}" {{DOMException}}
        if the [=cursor/source=] is not an [=/index=].
  </dl>
</div>



<div class=algorithm>

The <dfn method for=IDBCursor>advance(|count|)</dfn> method, when
invoked, must run these steps:

1. If |count| is 0 (zero), [=throw=] a [=TypeError=].

1. Let |transaction| be **this**'s [=cursor/transaction=].

1. If |transaction|'s [=transaction/state=] is not [=transaction/active=],
    then [=throw=] a "{{TransactionInactiveError}}" {{DOMException}}.

1. If **this**'s [=cursor/source=] or [=effective object
    store=] has been deleted, [=throw=] an "{{InvalidStateError}}" {{DOMException}}.

1. If **this**'s [=cursor/got value flag=] is false, indicating that
    the cursor is being iterated or has iterated past its end,
    [=throw=] an "{{InvalidStateError}}" {{DOMException}}.

1. Set **this**'s [=cursor/got value flag=] to false.

1. Let |request| be **this**'s [=cursor/request=].

1. Set |request|'s [=request/processed flag=] to false.

1. Set |request|'s [=request/done flag=] to false.

1. Run [=asynchronously execute a request=] with
    **this**'s [=cursor/source=] as |source|,
    [=iterate a cursor=] as |operation| and |request|, using
    the [=current Realm=] as |targetRealm|, **this**, and |count|.

</div>

<aside class=note>
  Calling this method more than once before new cursor data has been
  loaded - for example, calling {{advance()}} twice from the
  same onsuccess handler - results in an "{{InvalidStateError}}" {{DOMException}}
  being thrown on the second call because the cursor's
  [=cursor/got value flag=] has been set to false.
</aside>


<div class=algorithm>

The <dfn method for=IDBCursor>continue(|key|)</dfn> method, when
invoked, must run these steps:

1. Let |transaction| be **this**'s [=cursor/transaction=].

1. If |transaction|'s [=transaction/state=] is not [=transaction/active=],
    then [=throw=] a "{{TransactionInactiveError}}" {{DOMException}}.

1. If **this**'s [=cursor/source=] or
    [=effective object store=] has been deleted, [=throw=] an
    "{{InvalidStateError}}" {{DOMException}}.

1. If **this**'s [=cursor/got value flag=] is false, indicating that
    the cursor is being iterated or has iterated past its end,
    [=throw=] an "{{InvalidStateError}}" {{DOMException}}.

1. If |key| is given, then:

    1. Let |r| be the result of running [=convert a
        value to a key=] with |key|. Rethrow any exceptions.

    1. If |r| is invalid, [=throw=] a "{{DataError}}" {{DOMException}}.

    1. Let |key| be |r|.

    1. If |key| is [=less than=] or [=equal to=] **this**'s
        [=cursor/position=] and **this**'s [=cursor/direction=] is
        {{"next"}} or {{"nextunique"}}, then [=throw=] a "{{DataError}}" {{DOMException}}.

    1. If |key| is [=greater than=] or [=equal to=] **this**'s
        [=cursor/position=] and **this**'s [=cursor/direction=] is
        {{"prev"}} or {{"prevunique"}}, then [=throw=] a "{{DataError}}" {{DOMException}}.

1. Set **this**'s [=cursor/got value flag=] to false.

1. Let |request| be **this**'s [=cursor/request=].

1. Set |request|'s [=request/processed flag=] to false.

1. Set |request|'s [=request/done flag=] to false.

1. Run [=asynchronously execute a request=] with
    **this**'s [=cursor/source=] as |source|,
    [=iterate a cursor=] as |operation| and |request|,
    using the [=current Realm=] as |targetRealm|,
    **this**, and |key| (if given).

</div>

<aside class=note>
  Calling this method more than once before new cursor data has been
  loaded - for example, calling {{continue()}} twice from the
  same onsuccess handler - results in an "{{InvalidStateError}}" {{DOMException}}
  being thrown on the second call because the cursor's
  [=cursor/got value flag=] has been set to false.
</aside>


<div class=algorithm>

The <dfn method for=IDBCursor>continuePrimaryKey(|key|,
|primaryKey|)</dfn> method, when invoked, must run these steps:

1. Let |transaction| be **this**'s [=cursor/transaction=].

1. If |transaction|'s [=transaction/state=] is not [=transaction/active=],
    then [=throw=] a "{{TransactionInactiveError}}" {{DOMException}}.

1. If **this**'s [=cursor/source=] or [=effective object
    store=] has been deleted, [=throw=] an "{{InvalidStateError}}" {{DOMException}}.

1. If **this**'s [=cursor/source=] is not an
    [=/index=] [=throw=] an "{{InvalidAccessError}}" {{DOMException}}.

1. If **this**'s [=cursor/direction=] is not {{"next"}} or {{"prev"}},
    [=throw=] an "{{InvalidAccessError}}" {{DOMException}}.

1. If **this**'s [=cursor/got value flag=] is false, indicating that
    the cursor is being iterated or has iterated past its end,
    [=throw=] an "{{InvalidStateError}}" {{DOMException}}.

1. Let |r| be the result of running [=convert a value to
    a key=] with |key|. Rethrow any exceptions.

1. If |r| is invalid, [=throw=] a "{{DataError}}" {{DOMException}}.

1. Let |key| be |r|.

1. Let |r| be the result of running [=convert a value
     to a key=] with |primaryKey|. Rethrow any exceptions.

1. If |r| is invalid, [=throw=] a "{{DataError}}" {{DOMException}}.

1. Let |primaryKey| be |r|.

1. If |key| is [=less than=] **this**'s
    [=cursor/position=] and **this**'s [=cursor/direction=] is {{"next"}},
    [=throw=] a "{{DataError}}" {{DOMException}}.

1. If |key| is [=greater than=] **this**'s
    [=cursor/position=] and **this**'s [=cursor/direction=] is {{"prev"}},
    [=throw=] a "{{DataError}}" {{DOMException}}.

1. If |key| is [=equal to=] **this**'s [=cursor/position=] and
    |primaryKey| is [=less than=] or [=equal to=] **this**'s
    [=object store position=] and **this**'s [=cursor/direction=] is
    {{"next"}}, [=throw=] a "{{DataError}}" {{DOMException}}.

1. If |key| is [=equal to=] **this**'s [=cursor/position=] and
    |primaryKey| is [=greater than=] or [=equal to=] **this**'s
    [=object store position=] and **this**'s
    [=cursor/direction=] is {{"prev"}}, [=throw=] a
    "{{DataError}}" {{DOMException}}.

1. Set **this**'s [=cursor/got value flag=] to false.

1. Let |request| be **this**'s [=cursor/request=].

1. Set |request|'s [=request/processed flag=] to false.

1. Set |request|'s [=request/done flag=] to false.

1. Run [=asynchronously execute a request=] with
    **this**'s [=cursor/source=] as |source|,
    [=iterate a cursor=] as |operation| and |request|,
    using the [=current Realm=] as |targetRealm|,
    **this**, |key| and |primaryKey|.

</div>

<aside class=note>
  Calling this method more than once before new cursor data has been
  loaded - for example, calling {{continuePrimaryKey()}} twice from
  the same onsuccess handler - results in an "{{InvalidStateError}}" {{DOMException}}
  being thrown on the second call because the cursor's [=got value
  flag=] has been set to false.
</aside>



<div class=note>
  The following methods throw a "{{ReadOnlyError}}" {{DOMException}} if called within a
  [=read-only transaction=], and a "{{TransactionInactiveError}}" {{DOMException}} if
  called when the [=/transaction=] is not [=transaction/active=].

  <dl class=domintro>
    : |request| = |cursor| .
        {{IDBCursor/update()|update}}(|value|)
    ::
        Updated the [=object-store/record=] pointed at by the cursor with a new value.

        Throws a "{{DataError}}" {{DOMException}} if the [=cursor/effective object store=]
        uses [=in-line keys=] and the [=/key=] would have changed.

        If successful, |request|'s {{IDBRequest/result}} will be the
        [=object-store/record=]'s [=/key=].


    : |request| = |cursor| .
        {{IDBCursor/delete()|delete}}()
    ::
        Delete the [=object-store/record=] pointed at by the cursor with a new value.

        If successful, |request|'s {{IDBRequest/result}} will be
        `undefined`.
  </dl>
</div>

<div class=algorithm>

The <dfn method for=IDBCursor>update(|value|)</dfn> method, when
invoked, must run these steps:

1. Let |transaction| be **this**'s [=cursor/transaction=].

1. If |transaction|'s [=transaction/state=] is not [=transaction/active=],
    then [=throw=] a "{{TransactionInactiveError}}" {{DOMException}}.

1. If |transaction| is a [=read-only transaction=], [=throw=] a
    "{{ReadOnlyError}}" {{DOMException}}.

1. If **this**'s [=cursor/source=] or [=effective object
    store=] has been deleted, [=throw=] an "{{InvalidStateError}}" {{DOMException}}.

1. If **this**'s [=cursor/got value flag=] is false, indicating that
    the cursor is being iterated or has iterated past its end,
    [=throw=] an "{{InvalidStateError}}" {{DOMException}}.

1. If **this**'s [=cursor/key only flag=] is true, [=throw=] an
    "{{InvalidStateError}}" {{DOMException}}.

1. Let |targetRealm| be a user-agent defined [=Realm=].

1. Let |clone| be a [=clone=] of |value| in |targetRealm| during |transaction|.
    Rethrow any exceptions.

    <details class=note>
      <summary>Why create a copy of the value?</summary>
      The value is serialized when stored. Treating it as a copy
      here allows other algorithms in this specification to treat it as
      an ECMAScript value, but implementations can optimize this
      if the difference in behavior is not observable.
    </details>

1. If **this**'s [=effective object store=] uses [=in-line
    keys=], then:

    1. Let |kpk| be the result of running
        [=extract a key from a value using a key path=] with
        |clone| and the [=object-store/key
        path=] of **this**'s [=effective object store=].
        Rethrow any exceptions.

    1. If |kpk| is failure, invalid, or not [=equal to=]
        **this**'s [=effective key=], [=throw=] a
        "{{DataError}}" {{DOMException}}.

1. Return the result (an {{IDBRequest}}) of running
    [=asynchronously execute a request=]
    with **this** as |source| and [=store a
    record into an object store=] as |operation|, using **this**'s
    [=effective object store=] as |store|, the |clone| as
    |value|, **this**'s [=effective key=] as |key|, and with the
    |no-overwrite flag| false.

</div>

<aside class=note>
  A result of running the steps to [=store a record into an object
  store=] is that if the record has been deleted since the cursor
  moved to it, a new record will be created.
</aside>


<div class=algorithm>

The <dfn method for=IDBCursor>delete()</dfn> method, when invoked,
must run these steps:

1. Let |transaction| be **this**'s [=cursor/transaction=].

1. If |transaction|'s [=transaction/state=] is not [=transaction/active=],
    then [=throw=] a "{{TransactionInactiveError}}" {{DOMException}}.

1. If |transaction| is a [=read-only transaction=], [=throw=] a
    "{{ReadOnlyError}}" {{DOMException}}.

1. If **this**'s [=cursor/source=] or [=effective object
    store=] has been deleted, [=throw=] an "{{InvalidStateError}}" {{DOMException}}.

1. If **this**'s [=cursor/got value flag=] is false, indicating that
    the cursor is being iterated or has iterated past its end,
    [=throw=] an "{{InvalidStateError}}" {{DOMException}}.

1. If **this**'s [=cursor/key only flag=] is true, [=throw=] an
    "{{InvalidStateError}}" {{DOMException}}.

1. Return the result (an {{IDBRequest}}) of running
    [=asynchronously execute a request=]
    with **this** as |source| and
    [=delete records from an object store=] as |operation|, using
    **this**'s [=effective object store=] and [=effective
    key=] as |store| and |key| respectively.

</div>

A [=cursor=] that has its [=cursor/key only flag=] set to false implements the
{{IDBCursorWithValue}} interface as well.


<xmp class=idl>
[Exposed=(Window,Worker)]
interface IDBCursorWithValue : IDBCursor {
  readonly attribute any value;
};
</xmp>

<dl class="domintro note">
    : |cursor| . {{IDBCursorWithValue/value}}
    :: Returns the [=cursor=]'s current [=cursor/value=].
</dl>


The <dfn attribute for=IDBCursorWithValue>value</dfn> attribute's
getter must return **this**'s current [=cursor/value=]. Note
that if this property returns an object, it returns the same object
instance every time it is inspected, until the cursor's
[=cursor/value=] is changed. This means that if the object is
modified, those modifications will be seen by anyone inspecting the
value of the cursor. However modifying such an object does not modify
the contents of the database.


<!-- ============================================================ -->
## The {{IDBTransaction}} interface ## {#transaction}
<!-- ============================================================ -->

[=/transaction=] objects implement the following interface:

<xmp class=idl>
[Exposed=(Window,Worker)]
interface IDBTransaction : EventTarget {
  readonly attribute DOMStringList objectStoreNames;
  readonly attribute IDBTransactionMode mode;
  [SameObject] readonly attribute IDBDatabase db;
  readonly attribute DOMException? error;

  IDBObjectStore objectStore(DOMString name);
  void commit();
  void abort();

  // Event handlers:
  attribute EventHandler onabort;
  attribute EventHandler oncomplete;
  attribute EventHandler onerror;
};

enum IDBTransactionMode {
  "readonly",
  "readwrite",
  "versionchange"
};
</xmp>

<dl class="domintro note">
    : |transaction| . {{IDBTransaction/objectStoreNames}}
    ::
        Returns a list of the names of [=/object stores=] in the
        transaction's [=transaction/scope=]. For an [=/upgrade transaction=]
        this is all object stores in the [=database=].

    : |transaction| . {{IDBTransaction/mode}}
    ::
        Returns the [=transaction/mode=] the transaction was created with
        ({{"readonly"}} or {{"readwrite"}}), or {{"versionchange"}} for
        an [=/upgrade transaction=].

    : |transaction| . {{IDBTransaction/db}}
    ::
        Returns the transaction's [=transaction/connection=].

    : |transaction| . {{IDBTransaction/error}}
    ::
        If the transaction was [=transaction/aborted=], returns the
        error (a {{DOMException}}) providing the reason.
</dl>


<div class=algorithm>

The <dfn attribute for=IDBTransaction>objectStoreNames</dfn>
attribute's getter must run these steps:

1. If **this** is an [=/upgrade transaction=],
    then return a {{DOMStringList}} associated with a [=sorted name list=] of the [=object-store/names=]
    of the [=/object stores=] in **this**'s [=/connection=]'s [=object store set=].

1. Otherwise, return a {{DOMStringList}} associated with a [=sorted name list=] of the
    [=object-store/names=] of the [=/object stores=] in
    **this**'s [=transaction/scope=].

</div>

<aside class=note>
  The contents of each list returned by this attribute does not
  change, but subsequent calls to this attribute during an [=/upgrade
  transaction=] can return lists with different contents as
  [=/object stores=] are created and deleted.
</aside>

The <dfn attribute for=IDBTransaction>mode</dfn> attribute's getter
must return **this**'s [=transaction/mode=].

The <dfn attribute for=IDBTransaction>db</dfn> attribute's getter must
return **this**'s [=transaction/connection=]'s associated [=/database=].

The <dfn attribute for=IDBTransaction>error</dfn> attribute's getter
must return **this**'s [=transaction/error=], or null if
none.

<aside class=note>
  If this [=/transaction=] was aborted due to a failed
  [=/request=], this will be the same as the [=/request=]'s
  [=request/error=]. If this [=/transaction=] was aborted
  due to an uncaught exception in an event handler, the error will be
  a "{{AbortError}}" {{DOMException}}. If the [=/transaction=] was aborted due to
  an error while committing, it will reflect the reason for the
  failure (e.g. "{{QuotaExceededError}}", "{{ConstraintError}}", or
  "{{UnknownError}}" {{DOMException}}).
</aside>

<dl class="domintro note">
    : |transaction| .
        {{IDBTransaction/objectStore()|objectStore}}(|name|)
    ::
        Returns an {{IDBObjectStore}} in the [=/transaction=]'s [=transaction/scope=].

    : |transaction| . {{IDBTransaction/abort()}}
    ::
        Aborts the transaction. All pending [=/requests=] will fail with
        a "{{AbortError}}" {{DOMException}} and all changes made to the database will be
        reverted.

    : |transaction| . {{IDBTransaction/commit()}}
    ::
        Attempts to commit the transaction. All pending [=/requests=] will be allowed
        to complete, but no new requests will be accepted. This can be used to force a
        transaction to quickly finish, without waiting for pending requests to fire
        <a event>`success`</a> events before attempting to commit normally.

        The transaction will abort if a pending request fails, for example due to a
        constraint error. The <a event>`success`</a> events for successful requests
        will still fire, but throwing an exception in an event handler will not abort
        the transaction. Similarly, <a event>`error`</a> events for failed requests
        will still fire, but calling `preventDefault()` will not prevent the
        transaction from aborting.
</dl>

<div class=algorithm>

The <dfn method for=IDBTransaction>objectStore(|name|)</dfn> method,
when invoked, must run these steps:

1. If |transaction|'s [=transaction/state=] is [=transaction/finished=],
    then [=throw=] an "{{InvalidStateError}}" {{DOMException}}.

1. Let |store| be the [=/object store=]
    [=object-store/named=] |name| in **this**'s
    [=transaction/scope=], or [=throw=] a
    "{{NotFoundError}}" {{DOMException}} if none.

1. Return an [=/object store handle=] associated with |store|
    and **this**.

</div>

<aside class=note>
  Each call to this method on the same {{IDBTransaction}} instance
  with the same name returns the same {{IDBObjectStore}} instance.
</aside>

<aside class=note>
  The returned {{IDBObjectStore}} instance is specific to this
  {{IDBTransaction}}. If this method is called on a different
  {{IDBTransaction}}, a different {{IDBObjectStore}} instance is
  returned.
</aside>


<div class=algorithm>

The <dfn method for=IDBTransaction>abort()</dfn> method, when invoked,
must run these steps:

1. If **this**'s [=transaction/state=] is [=transaction/committing=]
    or [=transaction/finished=],
    then [=throw=] an "{{InvalidStateError}}" {{DOMException}}.

1. Set **this**'s [=transaction/state=] to [=transaction/inactive=] and run
    [=abort a transaction=] with null as |error|.

</div>

<div class=algorithm>

The <dfn method for=IDBTransaction>commit()</dfn> method, when invoked,
must run these steps:

1. If **this**'s [=transaction/state=] is not [=transaction/active=],
    then [=throw=] an "{{InvalidStateError}}" {{DOMException}}.

1. Run [=commit a transaction=] with **this**.

</div>

<aside class=advisement>
  &#x1F6A7;
  The {{IDBTransaction/commit()}} method is new in this edition.
  &#x1F6A7;
</aside>

<aside class=note>
    It is not normally necessary to call {{IDBTransaction/commit()}}
    on a [=/transaction=]. A transaction will automatically commit
    when all outstanding requests have been satisfied and no new
    requests have been made. This call can be used to start the
    [=transaction/commit=] process without waiting for events
    from outstanding [=/requests=] to be dispatched.
</aside>


The <dfn attribute for=IDBTransaction>onabort</dfn> attribute is the
event handler for the <a event>`abort`</a> event.

The <dfn attribute for=IDBTransaction>oncomplete</dfn> attribute is
the event handler for the <a event>`complete`</a> event.

The <dfn attribute for=IDBTransaction>onerror</dfn> attribute is the
event handler for the <a event>`error`</a> event.

<aside class=note>
  To determine if a [=/transaction=] has completed successfully,
  listen to the [=/transaction=]'s <a event>`complete`</a> event
  rather than the <a event>`success`</a> event of a particular
  [=/request=], because the [=/transaction=] can still fail after
  the <a event>`success`</a> event fires.
</aside>


<!-- ============================================================ -->
# Algorithms # {#algorithms}
<!-- ============================================================ -->

<!-- ============================================================ -->
## Opening a database ## {#opening}
<!-- ============================================================ -->

<div class=algorithm>

To <dfn>open a database</dfn> with |origin| which requested the [=database=] to be opened, a database |name|, a database |version|, and a |request|, run these steps:

1. Let |queue| be the [=connection queue=] for |origin| and |name|.

1. Add |request| to |queue|.

1. Wait until all previous requests in |queue| have been processed.

1. Let |db| be the [=database=] [=database/named=] |name| in
    |origin|, or null otherwise.

1. If |version| is undefined, let |version| be 1 if |db| is null, or
    |db|'s [=database/version=] otherwise.

1. If |db| is null, let |db| be a new [=database=] with
    [=database/name=] |name|, [=database/version=] 0 (zero), and with
    no [=/object stores=]. If this fails for any reason, return an
    appropriate error (e.g. a "{{QuotaExceededError}}" or
    "{{UnknownError}}" {{DOMException}}).

1. If |db|'s [=database/version=] is greater than |version|,
    return a newly [=exception/created=] "{{VersionError}}" {{DOMException}}
    and abort these steps.

1. Let |connection| be a new [=/connection=] to |db|.

1. Set |connection|'s [=connection/version=] to |version|.

1. If |db|'s [=database/version=] is less than |version|, then:

    1. Let |openConnections| be the [=/set=] of all [=/connections=],
        except |connection|, associated with |db|.

    1. [=set/For each=] |entry| of |openConnections| that does not have its
        [=close pending flag=] set to true, [=queue a task=] to [=fire a
        version change event=] named <a event>`versionchange`</a> at
        |entry| with |db|'s [=database/version=] and |version|.

        <aside class=note>
          Firing this event might cause one or more of the other
          objects in |openConnections| to be closed, in which case the
          <a event>`versionchange`</a> event is not fired at those
          objects, even if that hasn't yet been done.
        </aside>

    1. Wait for all of the events to be fired.

    1. If any of the [=/connections=] in |openConnections| are still
        not closed, [=queue a task=] to [=fire a version change
        event=] named <a event>`blocked`</a> at |request| with
        |db|'s [=database/version=] and |version|.

    1. <span id="version-change-close-block">Wait</span> until all
        [=/connections=] in |openConnections| are
        [=connection/closed=].

    1. Run [=run an upgrade transaction=]
        using |connection|, |version| and |request|.

    1. If |connection| was [=connection/closed=],
        return a newly [=exception/created=]
        "{{AbortError}}" {{DOMException}} and abort these steps.

    1. If the [=/upgrade transaction=] was aborted, run the steps
        to [=close a database connection=] with |connection|,
        return a newly [=exception/created=]
        "{{AbortError}}" {{DOMException}} and abort these steps.

1. Return |connection|.

</div>

<!-- ============================================================ -->
## Closing a database ## {#closing-connection}
<!-- ============================================================ -->

<div class=algorithm>

To <dfn>close a database connection</dfn> with a |connection| object, and an
optional |forced flag|, run these steps:

1. Set |connection|'s [=close pending flag=] to true.

1. If the |forced flag| is true, then for each |transaction|
    [=transaction/created=] using |connection| run [=abort a
    transaction=] with |transaction| and newly <a for=exception>created</a>
    "{{AbortError}}" {{DOMException}}.

1. Wait for all transactions [=transaction/created=] using |connection| to complete.
    Once they are complete, |connection| is [=connection/closed=].

1. If the |forced flag| is true, then [=fire an event=] named
    <a event>`close`</a> at |connection|.

    <aside class=note>
      The <a event>`close`</a> event only fires if the connection closes
      abnormally, e.g. if the origin's storage is cleared, or there is
      corruption or an I/O error. If {{IDBDatabase/close()}} is called explicitly
      the event *does not* fire.
    </aside>

</div>

<aside class=note>
  Once a [=/connection=]'s [=close pending flag=] has been set to true, no new transactions
  can be [=transaction/created=] using the [=/connection=]. All methods that
  [=transaction/create=] transactions first check the [=/connection=]'s [=close pending flag=]
  first and throw an exception if it is true.
</aside>

<aside class=note>
  Once the [=/connection=] is closed, this can unblock the steps to
  [=run an upgrade transaction=], and the steps to [=delete a
  database=], which [both](#delete-close-block)
  [wait](#version-change-close-block) for [=/connections=] to
  a given [=database=] to be closed before continuing.
</aside>


<!-- ============================================================ -->
## Deleting a database ## {#deleting-a-database}
<!-- ============================================================ -->

<div class=algorithm>

To <dfn>delete a database</dfn> with the |origin| that
requested the [=database=] to be deleted, a database |name|, and a
|request|, run these steps:

1. Let |queue| be the [=connection queue=] for |origin| and |name|.

1. Add |request| to |queue|.

1. Wait until all previous requests in |queue| have been processed.

1. Let |db| be the [=database=] [=database/named=] |name| in
    |origin|, if one exists. Otherwise, return 0 (zero).

1. Let |openConnections| be the [=/set=] of all [=/connections=]
    associated with |db|.

1. [=set/For each=] |entry| of |openConnections| that does not have its
    [=close pending flag=] set to true, [=queue a task=] to [=fire a version
    change event=] named <a event>`versionchange`</a> at |entry| with
    |db|'s [=database/version=] and null.

    <aside class=note>
      Firing this event might cause one or more of the other objects
      in |openConnections| to be closed, in which case the
      <a event>`versionchange`</a> event is not fired at those
      objects, even if that hasn't yet been done.
    </aside>

1. Wait for all of the events to be fired.

1. If any of the [=/connections=] in |openConnections| are still not
    closed, [=queue a task=] to [=fire a version change event=] named
    <a event>`blocked`</a> at |request| with |db|'s
    [=database/version=] and null.

1. <span id="delete-close-block">Wait</span> until all
    [=/connections=] in |openConnections| are
    [=connection/closed=].

1. Let |version| be |db|'s [=database/version=].

1. Delete |db|. If this fails for any reason, return an appropriate
    error (e.g. "{{QuotaExceededError}}" or "{{UnknownError}}" {{DOMException}}).

1. Return |version|.

</div>


<!-- ============================================================ -->
## Committing a transaction ## {#commit-transaction}
<!-- ============================================================ -->

<div class=algorithm>

To <dfn>commit a transaction</dfn> with the |transaction| to commit, run these steps:

1. Set |transaction|'s [=transaction/state=] to [=transaction/committing=].

1. Run the following steps [=in parallel=]:

    1. Wait until every item in |transaction|'s [=transaction/request list=]
        is [=request/processed=].

    1. If |transaction|'s [=transaction/state=] is no longer [=transaction/committing=],
        then terminate these steps.

    1. Attempt to write any outstanding changes made by |transaction| to the [=database=].

    1. If an error occurs while writing the changes to the [=database=],
        then run [=abort a transaction=] with |transaction| and an
        appropriate type for the error, for example "{{QuotaExceededError}}" or
        "{{UnknownError}}" {{DOMException}}, and terminate these steps.

    1. [=Queue a task=] to run these steps:

        1. If |transaction| is an [=/upgrade transaction=], then set |transaction|'s
            [=transaction/connection=]'s associated [=/database=]'s [=database/upgrade transaction=] to null.

        1. Set |transaction|'s [=transaction/state=] to [=transaction/finished=].

        1. [=Fire an event=] named <a event>`complete`</a> at |transaction|.

            <aside class=note>
              Even if an exception is thrown from one of the event handlers of
              this event, the transaction is still committed since writing the
              database changes happens before the event takes places. Only
              after the transaction has been successfully written is the
              <a event>`complete`</a> event fired.
            </aside>

        1. If |transaction| is an [=/upgrade transaction=], then
            let |request| be the [=/request=] associated with |transaction|
            and set |request|'s [=request/transaction=] to null.

</div>


<!-- ============================================================ -->
## Aborting a transaction ## {#abort-transaction}
<!-- ============================================================ -->

<div class=algorithm>

To <dfn>abort a transaction</dfn> with the |transaction| to abort, and |error|, run these steps:

1. All the changes made to the [=database=] by the [=/transaction=]
    are reverted. For [=/upgrade transactions=] this includes changes
    to the set of [=/object stores=] and [=/indexes=], as well as the
    change to the [=database/version=]. Any [=/object stores=] and
    [=/indexes=] which were created during the transaction are now
    considered deleted for the purposes of other algorithms.

1. If |transaction| is an [=/upgrade transaction=], run the steps
    to [=abort an upgrade transaction=] with |transaction|.

    <aside class=note>
      This reverts changes to all [=/connection=], [=/object store
      handle=], and [=index handle=] instances associated with
      |transaction|.
    </aside>

1. Set |transaction|'s [=transaction/state=] to [=transaction/finished=].

1. If |error| is not null, set |transaction|'s
    [=transaction/error=] to |error|.

1. [=list/For each=] |request| of |transaction|'s [=request list=],
    abort the steps to [=asynchronously execute a request=] for |request|,
    set |request|'s [=request/processed flag=] to true,
    and [=queue a task=] to run these steps:

    1. Set |request|'s [=request/done flag=] to true.
    1. Set |request|'s [=request/result=] to undefined.
    1. Set |request|'s [=request/error=] to a newly
        <a for=exception>created</a> "{{AbortError}}" {{DOMException}}.
    1. [=Fire an event=] named <a event>`error`</a> at |request|
        with its {{Event/bubbles}} and {{Event/cancelable}}
        attributes initialized to true.

    <aside class=note>
      This does not always result in any <a event>`error`</a> events
      being fired. For example if a transaction is aborted due to an
      error while [=transaction/committing=] the transaction,
      or if it was the last remaining request that failed.
    </aside>

1. [=Queue a task=] to run these steps:

    1. If |transaction| is an [=/upgrade transaction=], then set |transaction|'s
        [=transaction/connection=]'s associated [=/database=]'s [=database/upgrade transaction=] to null.

    1. [=Fire an event=] named <a event>`abort`</a> at |transaction|
        with its {{Event/bubbles}} attribute initialized to true.

    1. If |transaction| is an [=/upgrade transaction=], then:

        1. Let |request| be the [=request/open request=] associated with |transaction|.
        1. Set |request|'s [=request/transaction=] to null.
        1. Set |request|'s [=request/result=] to undefined.
        1. Set |request|'s [=request/processed flag=] to false.
        1. Set |request|'s [=request/done flag=] to false.

</div>


<!-- ============================================================ -->
## Asynchronously executing a [=/request=] ## {#async-execute-request}
<!-- ============================================================ -->

<div class=algorithm>

To <dfn>asynchronously execute a request</dfn> with the |source| object and an |operation| to perform on a database, and an optional |request|, run these steps:

These steps can be aborted at any point if the [=/transaction=] the
created [=/request=] belongs to is [=transaction/aborted=] using the steps to
[=abort a transaction=].

1. Let |transaction| be the [=/transaction=] associated with
    |source|.

1. [=/Assert=]: |transaction|'s [=transaction/state=] is [=transaction/active=].

1. If |request| was not given, let |request| be a new |request| with
    [=request/source=] as |source|.

1. Add |request| to the end of |transaction|'s [=request list=].

1. Run these steps [=in parallel=]:

    1. Wait until |request| is the first item in |transaction|'s [=transaction/request list=]
        that is not [=request/processed=].

    1. Let |result| be the result of performing |operation|.

    1. If |result| is an error and |transaction|'s [=transaction/state=] is [=committing=],
        then run [=abort a transaction=] with |transaction| and |error|,
        and terminate these steps.

    1. If |result| is an error,
        then revert all changes made by |operation|.

        <aside class=note>
          This only reverts the changes done by this request, not any
          other changes made by the transaction.
        </aside>

    1. Set |request|'s [=request/processed flag=] to true.

    1. [=Queue a task=] to run these steps:

        1. Remove |request| from |transaction|'s [=transaction/request list=].

        1. Set |request|'s [=request/done flag=] to true.

        1. If |result| is an error, then:

            1. Set |request|'s [=request/result=] to undefined.
            1. Set |request|'s [=request/error=] to |result|.
            1. [=Fire an error event=] at |request|.

        1. Otherwise:

            1. Set |request|'s [=request/result=] to |result|.
            1. Set |request|'s [=request/error=] to undefined.
            1. [=Fire a success event=] at |request|.

1. Return |request|.

</div>


<!-- ============================================================ -->
## Running an upgrade transaction ## {#upgrade-transaction-steps}
<!-- ============================================================ -->

<div class=algorithm>

To <dfn>run an upgrade transaction</dfn> with a |connection| object
which is used to update the [=database=], a new |version| to be set
for the [=database=], and a |request|, run these steps:

1. Let |db| be |connection|'s [=database=].

1. Let |transaction| be a new [=/upgrade transaction=] with
    |connection| used as [=/connection=]. The [=transaction/scope=] of
    |transaction| includes every [=/object store=] in
    |connection|.

1. Set |database|'s [=database/upgrade transaction=] to |transaction|.

1. Set |transaction|'s [=transaction/state=] to [=transaction/inactive=].

1. Start |transaction|.

    <aside class=note>
      Note that until this [=/transaction=] is finished, no
      other [=/connections=] can be opened to the same
      [=database=].
    </aside>

1. Let |old version| be |db|'s [=database/version=].

1. Set |db|'s [=database/version=] to |version|. This change is
    considered part of the [=/transaction=], and so if the
    transaction is [=transaction/aborted=], this change is reverted.

1. Set |request|'s [=request/processed flag=] to true.

1. [=Queue a task=] to run these steps:

    1. Set |request|'s [=request/result=] to |connection|.
    1. Set |request|'s [=request/transaction=] to |transaction|.
    1. Set |request|'s [=request/done flag=] to true.
    1. Set |transaction|'s [=transaction/state=] to [=transaction/active=].
    1. Let |didThrow| be the result of running
        [=fire a version change event=] named
        <a event>`upgradeneeded`</a> at |request| with |old
        version| and |version|.
    1. Set |transaction|'s [=transaction/state=] to [=transaction/inactive=].
    1. If |didThrow| is true, run [=abort a
        transaction=] with the |error| property set to a newly
        <a for=exception>created</a> "{{AbortError}}" {{DOMException}}.

1. Wait for |transaction| to [=transaction/finish=].

    <aside class=note>
      Some of the algorithms invoked during the [=/transaction=]'s
      [=transaction/lifetime=], such as the steps to [=commit a
      transaction=] and the steps to [=abort a transaction=],
      include steps specific to [=/upgrade transactions=].
    </aside>

</div>


<!-- ============================================================ -->
## Aborting an upgrade transaction ## {#abort-upgrade-transaction}
<!-- ============================================================ -->

<div class=algorithm>

To <dfn>abort an upgrade transaction</dfn> with |transaction|, run these steps:

<aside class=note>
  These steps are run as needed by the steps to [=abort a
  transaction=], which revert changes to the [=database=] including
  the set of associated [=/object stores=] and [=/indexes=], as well
  as the change to the [=database/version=].
</aside>

1. Let |connection| be |transaction|'s [=/connection=].

1. Let |database| be |connection|'s [=database=].

1. Set |connection|'s [=connection/version=] to |database|'s
    [=database/version=] if |database| previously existed, or 0 (zero)
    if |database| was newly created.

    <aside class=note>
      This reverts the value of {{IDBDatabase/version}} returned by the
      {{IDBDatabase}} object.
    </aside>

1. Set |connection|'s [=object store set=] to the set of
    [=/object stores=] in |database| if |database| previously
    existed, or the empty set if |database| was newly created.

    <aside class=note>
      This reverts the value of {{IDBDatabase/objectStoreNames}} returned
      by the {{IDBDatabase}} object.
    </aside>

1. For each [=/object store handle=] |handle| associated with
    |transaction|, including those for [=/object stores=] that
    were created or deleted during |transaction|:

    1. If |handle|'s [=object-store-handle/object store=] was not
        newly created during |transaction|, set |handle|'s
        [=object-store-handle/name=] to its
        [=object-store-handle/object store=]'s [=object-store/name=].

    1. Set |handle|'s [=index set=] to the set of [=/indexes=] that
        reference its [=object-store-handle/object store=].

    <aside class=note>
      This reverts the values of {{IDBObjectStore/name}} and
      {{IDBObjectStore/indexNames}} returned by related
      {{IDBObjectStore}} objects.
    </aside>

    <details class=note>
      <summary>How is this observable?</summary>
      Although script cannot access an [=/object store=] by using the
      {{objectStore()}} method on an {{IDBTransaction}} instance after
      the [=/transaction=] is aborted, it can still have references to
      {{IDBObjectStore}} instances where the {{IDBObjectStore/name}}
      and {{IDBObjectStore/indexNames}} properties can be queried.
    </details>

1. For each [=index handle=] |handle| associated with |transaction|,
    including those for [=/indexes=] that were created or deleted
    during |transaction|:

    1. If |handle|'s [=index-handle/index=] was not newly created
        during |transaction|, set |handle|'s [=index-handle/name=] to
        its [=index-handle/index=]'s [=index/name=].

    <aside class=note>
      This reverts the value of {{IDBIndex/name}} returned by related
      {{IDBIndex}} objects.
    </aside>

    <details class=note>
      <summary>How is this observable?</summary>
      Although script cannot access an [=/index=] by using the
      {{index()}} method on an {{IDBObjectStore}} instance after the
      [=/transaction=] is aborted, it can still have references to
      {{IDBIndex}} instances where the {{IDBIndex/name}} property can
      be queried.
    </details>

</div>

<aside class=note>
  The {{IDBDatabase/name}} property of the {{IDBDatabase}} instance is
  not modified, even if the aborted [=/upgrade transaction=] was
  creating a new [=database=].
</aside>


<!-- ============================================================ -->
## Firing a success event ## {#fire-success-event}
<!-- ============================================================ -->

<div class=algorithm>

To <dfn>fire a success event</dfn> at a |request|, run these steps:

1. Let |event| be the result of [=creating an event=] using {{Event}}.

1. Set |event|'s {{Event/type}} attribute to "`success`".

1. Set |event|'s {{Event/bubbles}} and {{Event/cancelable}} attributes to false.

1. Let |transaction| be |request|'s [=/transaction=].

1. Let |legacyOutputDidListenersThrowFlag| be initially false.

1. If |transaction|'s [=transaction/state=] is [=transaction/inactive=],
    then set |transaction|'s [=transaction/state=] to [=transaction/active=].

1. [=Dispatch=] |event| at |request| with |legacyOutputDidListenersThrowFlag|.

1. If |transaction|'s [=transaction/state=] is [=transaction/active=],
    then:

    1. Set |transaction|'s [=transaction/state=] to [=transaction/inactive=].

    1. If |legacyOutputDidListenersThrowFlag| is true,
        then run [=abort a transaction=] with
        |transaction| and a newly <a for=exception>created</a>
        "{{AbortError}}" {{DOMException}}.

    1. If |transaction|'s [=transaction/request list=] is empty,
        then run [=commit a transaction=] with |transaction|.

</div>


<!-- ============================================================ -->
## Firing an error event ## {#fire-error-event}
<!-- ============================================================ -->

<div class=algorithm>

To <dfn>fire an error event</dfn> at a |request|, run these steps:

1. Let |event| be the result of [=creating an event=] using {{Event}}.

1. Set |event|'s {{Event/type}} attribute to "`error`".

1. Set |event|'s {{Event/bubbles}} and {{Event/cancelable}} attributes to true.

1. Let |transaction| be |request|'s [=/transaction=].

1. Let |legacyOutputDidListenersThrowFlag| be initially false.

1. If |transaction|'s [=transaction/state=] is [=transaction/inactive=],
    then set |transaction|'s [=transaction/state=] to [=transaction/active=].

1. [=Dispatch=] |event| at [=/request=] with |legacyOutputDidListenersThrowFlag|.

1. If |transaction|'s [=transaction/state=] is [=transaction/active=],
    then:

    1. Set |transaction|'s [=transaction/state=] to [=transaction/inactive=].

    1. If |legacyOutputDidListenersThrowFlag| is true,
        then run [=abort a transaction=] with
        |transaction| and a newly <a for=exception>created</a>
        "{{AbortError}}" {{DOMException}} and terminate these steps.
        This is done even if |event|'s [=canceled flag=] is false.

        <aside class=note>
          This means that if an error event is fired and any of the event
          handlers throw an exception, |transaction|'s
          {{IDBTransaction/error}} property is set to an {{AbortError}}
          rather than |request|'s [=request/error=], even if
          {{Event/preventDefault()}} is never called.
        </aside>

    1. If |event|'s [=canceled flag=] is false,
        then run [=abort a transaction=] using
        |transaction| and [=/request=]'s [=request/error=], and
        terminate these steps.

    1. If |transaction|'s [=transaction/request list=] is empty,
        then run [=commit a transaction=] with |transaction|.

</div>

<!-- ============================================================ -->
## Clone a value ## {#clone-value}
<!-- ============================================================ -->

<div class=algorithm>

  To make a <dfn>clone</dfn> of |value| in |targetRealm| during |transaction|,
  run these steps:

  1. [=/Assert=]: |transaction|'s [=transaction/state=] is [=transaction/active=].

  1. Set |transaction|'s [=transaction/state=] to [=transaction/inactive=].

        <aside class=note>
          The [=/transaction=] is made [=transaction/inactive=] so that getters or other side effects triggered by the cloning operation are unable to make additional requests against the transaction.
        </aside>

  1. Let |serialized| be [=?=] <a abstract-op>StructuredSerializeForStorage</a>(|value|).

  1. Let |clone| be [=?=] <a abstract-op>StructuredDeserialize</a>(|serialized|, |targetRealm|).

  1. Set |transaction|'s [=transaction/state=] to [=transaction/active=].

  1. Return |clone|.

</div>


<!-- ============================================================ -->
# Database operations # {#database-operations}
<!-- ============================================================ -->

This section describes various operations done on the data in
[=/object stores=] and [=/indexes=] in a [=database=].
These operations are run by the steps to [=asynchronously execute
a request=].

<aside class=note>
  Invocations of <a abstract-op>StructuredDeserialize</a>() in the operation
  steps below can be asserted not to throw (as indicated by the [=!=] prefix)
  because they operate only on previous output of
  <a abstract-op>StructuredSerializeForStorage</a>().
</aside>

<!-- ============================================================ -->
## Object Store Storage Operation ## {#object-store-storage-operation}
<!-- ============================================================ -->

<div class=algorithm>

To <dfn>store a record into an object store</dfn> with
|store|, |value|, an optional |key|, and a |no-overwrite flag|, run these steps:

1. If |store| uses a [=key generator=], then:

    1. If |key| is undefined, then:

        1. Let |key| be the result of running
            [=generate a key=] for |store|.

        1. If |key| is failure, then this operation failed with a
            "{{ConstraintError}}" {{DOMException}}. Abort this
            algorithm without taking any further steps.

        1. If |store| also uses [=in-line keys=], then run
            [=inject a key into a value using a key path=]
            with |value|, |key| and |store|'s [=object-store/key
            path=].

    1. Otherwise, run [=possibly update the key generator=]
        for |store| with |key|.

1. If the |no-overwrite flag| was given to these steps and is true, and
    a [=object-store/record=] already exists in |store| with its key [=equal to=]
    |key|, then this operation failed with a "{{ConstraintError}}" {{DOMException}}.
    Abort this algorithm without taking any further steps.

1. If a [=object-store/record=] already exists in |store| with its key [=equal
    to=] |key|, then remove the [=object-store/record=] from |store| using
    [=delete records from an object store=].

1. Store a record in |store| containing |key| as its key and
    [=!=] <a abstract-op>StructuredSerializeForStorage</a>(|value|)
    as its value. The record is stored in the object store's
    [=object-store/list of records=] such that the list is sorted
    according to the key of the records in [=ascending=] order.

1. For each |index| which [=references=] |store|:

    1. Let |index key| be the result of running
        [=extract a key from a value using a key path=] with
        |value|, |index|'s [=index/key path=], and |index|'s
        [=multiEntry flag=].

    1. If |index key| is an exception, or invalid, or failure, take no
        further actions for |index|, and continue these steps
        for the next index.

        <aside class=note>
          An exception thrown in this step is not rethrown.
        </aside>

    1. If |index|'s [=multiEntry flag=] is false, or if |index key|
        is not an [=array key=], and if |index| already contains a
        [=object-store/record=] with [=/key=] [=equal to=] |index
        key|, and |index|'s [=unique flag=] is true, then this
        operation failed with a "{{ConstraintError}}" {{DOMException}}. Abort this
        algorithm without taking any further steps.

    1. If |index|'s [=multiEntry flag=] is true and |index key| is
        an [=array key=], and if |index| already contains a
        [=object-store/record=] with [=/key=] [=equal to=] any of the
        [=subkeys=] of |index key|, and |index|'s [=unique
        flag=] is true, then this operation failed with a
        "{{ConstraintError}}" {{DOMException}}. Abort this algorithm without taking any
        further steps.

    1. If |index|'s [=multiEntry flag=] is false, or if |index key|
        is not an [=array key=] then store a record in |index|
        containing |index key| as its key and |key| as its value. The
        record is stored in |index|'s [=index/list of records=]
        such that the list is sorted primarily on the records keys,
        and secondarily on the records values, in [=ascending=] order.

    1. If |index|'s [=multiEntry flag=] is true and |index key| is
        an [=array key=], then for each |subkey| of the
        [=subkeys=] of |index key| store a record in |index|
        containing |subkey| as its key and |key| as its value. The
        records are stored in |index|'s [=index/list of
        records=] such that the list is sorted primarily on the
        records keys, and secondarily on the records values, in
        [=ascending=] order.

        <aside class=note>
          It is valid for there to be no [=subkeys=]. In this case
          no records are added to the index.
        </aside>

        <aside class=note>
          Even if any member of [=subkeys=] is itself an [=array key=],
          the member is used directly as the key for the index record.
          Nested [=array keys=] are not flattened or "unpacked" to
          produce multiple rows; only the outer-most [=array key=] is.
        </aside>

1. Return |key|.

</div>


<!-- ============================================================ -->
## Object Store Retrieval Operations ## {#object-store-retrieval-operation}
<!-- ============================================================ -->

<div class=algorithm>

To <dfn>retrieve a value from an object store</dfn> with
|targetRealm|, |store| and |range|, run these steps:

1. Let |record| be the first [=object-store/record=] in |store|'s
    [=object-store/list of records=] whose [=/key=] is [=in=] |range|, if
    any.

1. If |record| was not found, return undefined.

1. Let |serialized| be of |record|'s [=/value=].

1. Return [=!=] <a abstract-op>StructuredDeserialize</a>(|serialized|, |targetRealm|).

</div>


<div class=algorithm>

To <dfn>retrieve multiple values from an object
store</dfn> with |targetRealm|, |store|, |range| and optional |count|, run these steps:

1. If |count| is not given or is 0 (zero), let |count| be infinity.

1. Let |records| be a [=/list=] containing the first |count| [=object-store/records=]
    in |store|'s [=object-store/list of records=] whose [=/key=] is
    [=in=] |range|.

1. Let |list| be an empty list.

1. [=list/For each=] |record| of |records|:

    1. Let |serialized| be |record|'s [=/value=].
    1. Let |entry| be [=!=] <a abstract-op>StructuredDeserialize</a>(|serialized|, |targetRealm|).
    1. Append |entry| to |list|.

1. Return |list| converted to a [=sequence&lt;any&gt;=].

</div>


<div class=algorithm>

To <dfn>retrieve a key from an object store</dfn>
with |store| and |range|, run these steps:

1. Let |record| be the first [=object-store/record=] in |store|'s
    [=object-store/list of records=] whose [=/key=] is [=in=] |range|, if
    any.

1. If |record| was not found, return undefined.

1. Return the result of running [=convert a
    key to a value=] with |record|'s key.

</div>


<div class=algorithm>

To <dfn>retrieve multiple keys from an object store</dfn>
with |store|, |range| and optional |count|, run these steps:

1. If |count| is not given or is 0 (zero), let |count| be infinity.

1. Let |records| be a list containing the first |count| [=object-store/records=]
    in |store|'s [=object-store/list of records=] whose [=/key=] is
    [=in=] |range|.

1. Let |list| be an empty [=/list=].

1. [=list/For each=] |record| of |records|:

    1. Let |entry| be the result of running [=convert a
        key to a value=] with |record|'s key.
    1. Append |entry| to |list|.

1. Return |list| converted to a [=sequence&lt;any&gt;=].

</div>


<!-- ============================================================ -->
## Index Retrieval Operations ## {#index-retrieval-operation}
<!-- ============================================================ -->

<div class=algorithm>

To <dfn>retrieve a referenced value from an index</dfn>
with |targetRealm|, |index| and |range|, run these steps:

1. Let |record| be the first [=object-store/record=] in |index|'s [=index/list of
    records=] whose [=index/key=] is [=in=] |range|, if any.

1. If |record| was not found, return undefined.

1. Let |serialized| be |record|'s [=referenced value=].

1. Return [=!=] <a abstract-op>StructuredDeserialize</a>(|serialized|, |targetRealm|).

</div>


<div class=algorithm>

To <dfn>retrieve multiple referenced values from an
index</dfn> with |targetRealm|, |index|, |range| and optional |count|, run these steps:

1. If |count| is not given or is 0 (zero), let |count| be infinity.

1. Let |records| be a list containing the first |count| [=object-store/records=]
    in |index|'s [=index/list of records=] whose [=index/key=] is [=in=] |range|.

1. Let |list| be an empty [=/list=].

1. [=list/For each=] |record| of |records|:

    1. Let |serialized| be |record|'s [=referenced value=].
    1. Let |entry| be [=!=] <a abstract-op>StructuredDeserialize</a>(|serialized|, |targetRealm|).
    1. Append |entry| to |list|.

1. Return |list| converted to a [=sequence&lt;any&gt;=].

</div>

<aside class=note>
    The [=index/values=] of an [=index/record=] in an index are the keys of
    [=object-store/records=] in the [=index/referenced=] object store.
</aside>

<div class=algorithm>

To <dfn>retrieve a value from an index</dfn> with
|index| and |range|, run these steps:

1. Let |record| be the first [=index/record=] in |index|'s [=index/list of
    records=] whose [=index/key=] is [=in=] |range|, if any.

1. If |record| was not found, return undefined.

1. Return the result of running [=convert a
        key to a value=] with |record|'s [=/value=].

</div>


<div class=algorithm>

To <dfn>retrieve multiple values from an index</dfn> with
|index|, |range| and optional |count|, run these steps:

1. If |count| is not given or is 0 (zero), let |count| be infinity.

1. Let |records| be a list containing the first |count| [=index/records=] in
    |index|'s [=index/list of records=] whose [=index/key=] is [=in=] |range|.

1. Let |list| be an empty [=/list=].

1. [=list/For each=] |record| of |records|:

    1. Let |entry| be the result of running [=convert a
        key to a value=] with |record|'s value.
    1. Append |entry| to |list|.

1. Return |list| converted to a [=sequence&lt;any&gt;=].

</div>


<!-- ============================================================ -->
## Object Store Deletion Operation ## {#object-store-deletion-operation}
<!-- ============================================================ -->

<div class=algorithm>

To <dfn>delete records from an object store</dfn>
with |store| and |range|, run these steps:

1. Remove all records, if any, from |store|'s [=object-store/list
    of records=] with key [=in=]
    |range|.

1. For each |index| which [=references=] |store|, remove every
    [=object-store/record=] from |index|'s [=index/list of records=] whose value is
    [=in=] |range|, if any such records exist.

1. Return undefined.

</div>


<!-- ============================================================ -->
## Record Counting Operation ## {#record-counting-operation}
<!-- ============================================================ -->

<div class=algorithm>

To <dfn>count the records in a range</dfn> with |source| and
|range|, run these steps:

1. Let |count| be the number of records, if any, in |source|'s list of
    records with key [=in=] |range|.

1. Return |count|.

</div>


<!-- ============================================================ -->
## Object Store Clear Operation ## {#object-store-clear-operation}
<!-- ============================================================ -->

<div class=algorithm>

To <dfn>clear an object store</dfn> with |store|, run these steps:

1. Remove all records from |store|.

1. In all [=/indexes=] which [=reference=] |store|, remove all
    [=object-store/records=].

1. Return undefined.

</div>


<!-- ============================================================ -->
## Cursor Iteration Operation ## {#cursor-iteration-operation}
<!-- ============================================================ -->

<div class=algorithm>

To <dfn>iterate a cursor</dfn> with |targetRealm|, |cursor|, an optional
|key| and |primaryKey| to iterate to, and an optional |count|, run these steps:

1. Let |source| be |cursor|'s [=cursor/source=].

1. Let |direction| be |cursor|'s [=cursor/direction=].

1. [=/Assert=]: if |primaryKey| is given, |source| is an [=/index=]
    and |direction| is {{"next"}} or {{"prev"}}.

1. Let |records| be the list of [=object-store/records=] in |source|.

    <aside class=note>
      |records| is always sorted in [=ascending=] [=/key=] order.
      In the case of |source| being an [=/index=], |records|
      is secondarily sorted in [=ascending=] [=/value=] order
      (where the value in an [=/index=] is the
      [=/key=] of the [=object-store/record=] in the referenced
      [=/object store=]).
    </aside>

1. Let |range| be |cursor|'s [=cursor/range=].

1. Let |position| be |cursor|'s [=cursor/position=].

1. Let |object store position| be |cursor|'s [=object store position=].

1. If |count| is not given, let |count| be 1.

1. While |count| is greater than 0:

    1. Switch on |direction|:

        <dl class=switch>
          : {{"next"}}
          ::
              Let |found record| be the first record in |records| which
              satisfy all of the following requirements:

              * If |key| is defined, the record's key is [=greater
                  than=] or [=equal to=] |key|.

              * If |primaryKey| is defined, the record's key is [=equal
                  to=] |key| and the record's value is [=greater
                  than=] or [=equal to=] |primaryKey|, or the
                  record's key is [=greater than=] |key|.

              * If |position| is defined, and |source| is an
                  [=/object store=], the record's key is [=greater than=]
                  |position|.

              * If |position| is defined, and |source| is an
                  [=/index=], the record's key is [=equal to=]
                  |position| and the record's value is [=greater
                  than=] |object store position| or the record's key is
                  [=greater than=] |position|.

              * The record's key is [=in=]
                  |range|.

          : {{"nextunique"}}
          ::
              Let |found record| be the first record in |records| which
              satisfy all of the following requirements:

              * If |key| is defined, the record's key is [=greater
                  than=] or [=equal to=] |key|.

              * If |position| is defined, the record's key is [=greater
                  than=] |position|.

              * The record's key is [=in=]
                  |range|.

          : {{"prev"}}
          ::
              Let |found record| be the last record in |records| which
              satisfy all of the following requirements:

              * If |key| is defined, the record's key is [=less
                  than=] or [=equal to=] |key|.

              * If |primaryKey| is defined, the record's key is [=equal
                  to=] |key| and the record's value is [=less than=]
                  or [=equal to=] |primaryKey|, or the record's key is
                  [=less than=] |key|.

              * If |position| is defined, and |source| is an
                  [=/object store=], the record's key is [=less
                  than=] |position|.

              * If |position| is defined, and |source| is an
                  [=/index=], the record's key is [=equal to=]
                  |position| and the record's value is [=less than=]
                  |object store position| or the record's key is
                  [=less than=] |position|.

              * The record's key is [=in=] |range|.

          : {{"prevunique"}}
          ::
              Let |temp record| be the last record in
              |records| which satisfy all of the following requirements:

              * If |key| is defined, the record's key is [=less
                  than=] or [=equal to=] |key|.

              * If |position| is defined, the record's key is [=less
                  than=] |position|.

              * The record's key is [=in=]
                  |range|.

              If |temp record| is defined, let |found record| be the
              first record in |records| whose [=/key=] is [=equal to=]
              |temp record|'s [=/key=].

              <aside class=note>
                Iterating with {{"prevunique"}} visits the same records that
                {{"nextunique"}} visits, but in reverse order.
              </aside>

        </dl>

    1. If |found record| is not defined, then:

        1. Set |cursor|'s [=cursor/key=] to undefined.

        1. If |source| is an [=/index=], set |cursor|'s
            [=object store position=] to undefined.

        1. If |cursor|'s [=cursor/key only flag=] is false, set |cursor|'s
            [=cursor/value=] to undefined.

        1. Return null.

    1. Let |position| be |found record|'s key.

    1. If |source| is an [=/index=], let |object store
        position| be |found record|'s value.

    1. Decrease |count| by 1.

1. Set |cursor|'s [=cursor/position=] to |position|.

1. If |source| is an [=/index=], set |cursor|'s [=object
    store position=] to |object store position|.

1. Set |cursor|'s [=cursor/key=] to |found record|'s key.

1. If |cursor|'s [=cursor/key only flag=] is false, then:

    1. Let |serialized| be |found record|'s [=referenced value=].
    1. Set |cursor|'s [=cursor/value=] to
        [=!=] <a abstract-op>StructuredDeserialize</a>(|serialized|, |targetRealm|)

1. Set |cursor|'s [=cursor/got value flag=] to true.

1. Return |cursor|.

</div>


<!-- ============================================================ -->
# ECMAScript binding # {#binding}
<!-- ============================================================ -->

This section defines how [=/key=] values defined in this specification
are converted to and from ECMAScript values, and how they may be
extracted from and injected into ECMAScript values using [=/key
paths=]. This section references types and algorithms and uses some
algorithm conventions from the ECMAScript Language Specification.
[[!ECMA-262]] Conversions not detailed here are defined in [[!WEBIDL]].


<!-- ============================================================ -->
## Extract a key from a value ## {#extract-key-from-value}
<!-- ============================================================ -->

<div class=algorithm>

To <dfn>extract a key from a value using a key path</dfn>
with |value|, |keyPath| and an optional |multiEntry flag|, run the
following steps. The result of these steps is a [=/key=], invalid, or
failure, or the steps may throw an exception.

1. Let |r| be the result of running [=evaluate a key
    path on a value=] with |value| and |keyPath|. Rethrow any
    exceptions.

1. If |r| is failure, return failure.

1. Let |key| be the result of running [=convert a value
    to a key=] with |r| if the |multiEntry flag| is false, and the
    result of running [=convert a value to a multiEntry
    key=] with |r| otherwise. Rethrow any exceptions.

1. If |key| is invalid, return invalid.

1. Return |key|.

</div>


<div class=algorithm>

To <dfn>evaluate a key path on a value</dfn> with |value|
and |keyPath|, run the following steps. The result of these steps is an
ECMAScript value or failure, or the steps may throw an exception.

1. If |keyPath| is a [=/list=] of strings, then:

    1. Let |result| be a new [=Array=] object created as if by the
        expression `[]`.

    1. Let |i| be 0.

    1. [=list/For each=] |item| of |keyPath|:

        1. Let |key| be the result of recursively running
            [=evaluate a key path on a value=] using
            |item| as |keyPath| and |value| as |value|.

        1. [=/Assert=]: |key| is not an [=abrupt completion=].

        1. If |key| is failure, abort the overall algorithm and return
            failure.

        1. Let |p| be [=!=] [=ToString=](|i|).

        1. Let |status| be [=CreateDataProperty=](|result|, |p|, |key|).

        1. [=/Assert=]: |status| is true.

        1. Increase |i| by 1.

    1. Return |result|.

        <aside class=note>
          This will only ever "recurse" one level since [=/key
          path=] sequences can't ever be nested.
        </aside>

1. If |keyPath| is the empty string, return |value| and skip the
    remaining steps.

1. Let |identifiers| be the result of
    <a lt="strictly split a string">strictly splitting</a>
    |keyPath| on U+002E FULL STOP characters (.).

1. [=list/For each=] |identifier| of |identifiers|, jump to the appropriate step below:

    <dl class=switch>
      : If [=/Type=](|value|) is String, and |identifier| is "`length`"
      :: Let |value| be a Number equal to the number of elements in |value|.

      : If |value| is an [=Array=] and |identifier| is "`length`"
      :: Let |value| be [=!=] [=ToLength=]([=!=] [=Get=](|value|, "`length`")).

      : If |value| is a {{Blob}} and |identifier| is "`size`"
      :: Let |value| be a Number equal to |value|'s {{Blob/size}}.

      : If |value| is a {{Blob}} and |identifier| is "`type`"
      :: Let |value| be a String equal to |value|'s {{Blob/type}}.

      : If |value| is a {{File}} and |identifier| is "`name`"
      :: Let |value| be a String equal to |value|'s {{File/name}}.

      : If |value| is a {{File}} and |identifier| is "`lastModified`"
      :: Let |value| be a Number equal to |value|'s {{File/lastModified}}.

      : Otherwise
      ::
          1. If [=/Type=](|value|) is not Object, return failure.

          1. Let |hop| be [=!=] [=HasOwnProperty=](|value|, |identifier|).

          1. If |hop| is false, return failure.

          1. Let |value| be [=!=] [=Get=](|value|, |identifier|).

          1. If |value| is undefined, return failure.

    </dl>

1. [=/Assert=]: |value| is not an [=abrupt completion=].

1. Return |value|.

</div>

<aside class=note>
  Assertions can be made in the above steps because this algorithm is
  only applied to values that are the output of <a abstract-op>StructuredDeserialize</a>
  and only access "own" properties.
</aside>


<!-- ============================================================ -->
## Inject a key into a value ## {#inject-key-into-value}
<!-- ============================================================ -->

<aside class=note>
  The [=/key paths=] used in this section are always strings and never
  sequences, since it is not possible to create a [=/object store=] which has a
  [=key generator=] and also has a [=object-store/key path=] that is a
  sequence.
</aside>

<div class=algorithm>

To <dfn>check that a key could be injected into a value</dfn> with |value| and a |keyPath|, run the following steps.
The result of these steps is either true or false.

<div class=algorithm>

1. Let |identifiers| be the result of <a lt="strictly split a string">strictly splitting</a>
    |keyPath| on U+002E FULL STOP characters (.).

1. [=/Assert=]: |identifiers| is not empty.

1. Remove the last [=list/item=] of |identifiers|.

1. [=list/For each=] remaining |identifier| of |identifiers|, if any:

    1. If |value| is not an [=Object=] or an [=Array=], return false.

    1. Let |hop| be [=!=] [=HasOwnProperty=](|value|, |identifier|).

    1. If |hop| is false, return true.

    1. Let |value| be [=!=] [=Get=](|value|, |identifier|).

1. Return true if |value| is an [=Object=] or an [=Array=], or false otherwise.

</div>

<aside class=note>
  Assertions can be made in the above steps because this algorithm is
  only applied to values that are the output of <a abstract-op>StructuredDeserialize</a>.
</aside>

<div class=algorithm>

To <dfn>inject a key into a value using a key path</dfn> with |value|, a |key| and a |keyPath|, run these steps:

1. Let |identifiers| be the result of <a lt="strictly split a string">strictly splitting</a>
    |keyPath| on U+002E FULL STOP characters (.).

1. [=/Assert=]: |identifiers| is not empty.

1. Let |last| be the last [=list/item=] of |identifiers| and remove it from
    the list.

1. [=list/For each=] remaining |identifier| of |identifiers|:

    1. [=/Assert=]: |value| is an [=Object=] or an [=Array=].

    1. Let |hop| be [=!=] [=HasOwnProperty=](|value|, |identifier|).

    1. If |hop| is false, then:

         1. Let |o| be a new [=Object=] created as if by the
            expression `({})`.

         1. Let |status| be [=CreateDataProperty=](|value|, |identifier|,
            |o|).

         1. [=/Assert=]: |status| is true.

    1. Let |value| be [=!=] [=Get=](|value|, |identifier|).

1. [=/Assert=]: |value| is an [=Object=] or an [=Array=].

1. Let |keyValue| be the result of running [=convert a
    key to a value=] with |key|.

1. Let |status| be [=CreateDataProperty=](|value|, |last|, |keyValue|).

1. [=/Assert=]: |status| is true.

</div>

<aside class=note>
  Assertions can be made in the above steps because this algorithm is
  only applied to values that are the output of <a abstract-op>StructuredDeserialize</a>,
  and the steps to [=check that a key could be injected into a value=] have
  been run.
</aside>


<!-- ============================================================ -->
## Convert a key to a value ## {#convert-key-to-value}
<!-- ============================================================ -->

<div class=algorithm>

To <dfn>convert a key to a value</dfn> with |key|, run the following steps.
The steps return an ECMAScript value.

1. Let |type| be |key|'s [=key/type=].

1. Let |value| be |key|'s [=key/value=].

1. Switch on |type|:

    <dl class=switch>
      : *number*
      :: Return an ECMAScript Number value equal to |value|

      : *string*
      :: Return an ECMAScript String value equal to |value|

      : *date*
      ::
          1. Let |date| be the result of executing the ECMAScript Date
              constructor with the single argument |value|.
          1. [=/Assert=]: |date| is not an [=abrupt completion=].
          1. Return |date|.

      : *binary*
      ::
          1. Let |len| be |value|'s [=byte sequence/length=].
          1. Let |buffer| be the result of executing the ECMAScript
              ArrayBuffer constructor with |len|.
          1. [=/Assert=]: |buffer| is not an [=abrupt completion=].
          1. Set the entries in |buffer|'s
              \[[ArrayBufferData]] internal slot to the entries
              in |value|.
          1. Return |buffer|.

      : *array*
      ::
          1. Let |array| be the result of executing the ECMAScript Array
              constructor with no arguments.
          1. [=/Assert=]: |array| is not an [=abrupt completion=].
          1. Let |len| be |value|'s [=list/size=].
          1. Let |index| be 0.
          1. While |index| is less than |len|:

              1. Let |entry| be the result of running
                  [=convert a key to a value=] with |value|[|index|].
              1. Let |status| be [=CreateDataProperty=](|array|, |index|,
                  |entry|).
              1. [=/Assert=]: |status| is true.
              1. Increase |index| by 1.

          1. Return |array|.

    </dl>

</div>


<!-- ============================================================ -->
## Convert a value to a key ## {#convert-value-to-key}
<!-- ============================================================ -->

<div class=algorithm>

To <dfn>convert a value to a key</dfn> with an ECMAScript value |input|, and an optional
[=/set=] |seen|, run the following steps.
The result of these steps is a [=/key=] or invalid, or the
steps may throw an exception.

1. If |seen| was not given, then let |seen| be a new empty [=/set=].

1. If |seen| [=set/contains=] |input|, then return invalid.

1. Jump to the appropriate step below:

    <dl class=switch>

      <!-- Number -->
      : If [=/Type=](|input|) is Number
      ::
          1. If |input| is NaN then return invalid.
          1. Otherwise, return a new [=/key=] with
              [=key/type=] *number* and [=key/value=]
              |input|.

      <!-- Date -->
      : If |input| is a [=Date=] (has a \[[DateValue]] internal slot)
      ::
          1. Let |ms| be the value of |input|'s
              \[[DateValue]] internal slot.

          1. If |ms| is NaN then return invalid.

          1. Otherwise, return a new [=/key=] with [=key/type=]
              *date* and [=key/value=] |ms|.

      <!-- String -->
      : If [=/Type=](|input|) is String
      ::
          1. Return a new [=/key=] with [=key/type=] *string* and
              [=key/value=] |input|.


      <!-- Binary -->
      : If |input| is a [=buffer source type=]
      ::
          1. Let |bytes| be the result of running
              <a lt="get a copy of the buffer source">get a copy of the bytes held by the buffer source</a>
              |input|. Rethrow any exceptions.

          1. Return a new [=/key=] with [=key/type=]
              *binary* and [=key/value=] |bytes|.

      <!-- Array -->
      : If |input| is an [=/Array exotic object=]
      ::
          1. Let |len| be [=?=] [=ToLength=]( [=?=] [=Get=](|input|,
              "`length`")).
          1. [=set/Append=] |input| to |seen|.
          1. Let |keys| be a new empty list.
          1. Let |index| be 0.
          1. While |index| is less than |len|:

              1. Let |hop| be [=?=] [=HasOwnProperty=](|input|, |index|).

              1. If |hop| is false, return invalid.

              1. Let |entry| be [=?=] [=Get=](|input|, |index|).

              1. Let |key| be the result of running
                  [=convert a value to a key=] with arguments |entry|
                  and |seen|.

              1. [=ReturnIfAbrupt=](|key|).

              1. If |key| is invalid abort these steps and return
                  invalid.

              1. [=list/Append=] |key| to |keys|.

              1. Increase |index| by 1.

          1. Return a new [=array key=] with [=key/value=]
              |keys|.


      : Otherwise
      :: Return invalid.

    </dl>

</div>


<div class=algorithm>

To <dfn>convert a value to a multiEntry key</dfn> with an ECMAScript value |input|, run the following steps.
The result of these steps is a [=/key=] or invalid, or the
steps may throw an exception.

1. If |input| is an [=/Array exotic object=], then:

    1. Let |len| be [=?=] ToLength( [=?=] [=Get=](|input|, "`length`")).

    1. Let |seen| be a new [=/set=] containing only |input|.

    1. Let |keys| be a new empty [=/list=].

    1. Let |index| be 0.

    1. While |index| is less than |len|:

        1. Let |entry| be [=Get=](|input|, |index|).

        1. If |entry| is not an [=abrupt completion=], then:

             1. Let |key| be the result of running
                 [=convert a value to a key=] with arguments
                 |entry| and |seen|.

             1. If |key| is not invalid or an [=abrupt completion=],
                 and there is no [=list/item=] in |keys| [=equal to=] |key|,
                 then [=list/append=] |key| to |keys|.

        1. Increase |index| by 1.

    1. Return a new [=array key=] with [=key/value=] set to |keys|.

1. Otherwise, return the result of running [=convert a
    value to a key=] with argument |input|.
    Rethrow any exceptions.

</div>

<aside class=note>
  These steps are similar to those to [=convert a value to a key=]
  but if the top-level value is an [=Array=] then members which can
  not be converted to keys are ignored, and duplicates are removed.

  For example, the value `[10, 20, null, 30, 20]` is
  converted to an [=array key=] with [=subkeys=] 10, 20, 30.
</aside>


<!-- ============================================================ -->
# Privacy Considerations # {#privacy}
<!-- ============================================================ -->

*This section is non-normative.*

## User tracking ## {#user-tracking}

A third-party host (or any object capable of getting content
distributed to multiple sites) could use a unique identifier stored in
its client-side database to track a user across multiple sessions,
building a profile of the user's activities. In conjunction with a
site that is aware of the user's real id object (for example an
e-commerce site that requires authenticated credentials), this could
allow oppressive groups to target individuals with greater accuracy
than in a world with purely anonymous Web usage.

There are a number of techniques that can be used to mitigate the risk
of user tracking:


: Blocking third-party storage
::
    User agents may restrict access to the database objects
    to scripts originating at the domain of the top-level document of
    the <span>browsing context</span>, for instance denying access to
    the API for pages from other domains running in `iframe`s.

: Expiring stored data
::
    User agents may automatically delete stored data after a period of
    time.

    This can restrict the ability of a site to track a user, as the site
    would then only be able to track the user across multiple sessions
    when she authenticates with the site itself (e.g. by making a purchase
    or logging in to a service).

    However, this also puts the user's data at risk.

: Treating persistent storage as cookies
::
    User agents should present the database feature to the user in a way
    that associates them strongly with HTTP session cookies. [[COOKIES]]

    This might encourage users to view such storage with healthy
    suspicion.

: Site-specific safe-listing of access to databases
::
    User agents may require the user to authorize access to databases
    before a site can use the feature.

: Origin-tracking of stored data
::
    User agents may record the [=/origins=] of sites that contained content
    from third-party origins that caused data to be stored.

    If this information is then used to present the view of data
    currently in persistent storage, it would allow the user to make
    informed decisions about which parts of the persistent storage to
    prune. Combined with a blocklist ("delete this data and prevent
    this domain from ever storing data again"), the user can restrict
    the use of persistent storage to sites that she trusts.

: Shared blocklists
::
    User agents may allow users to share their persistent storage
    domain blocklists.

    This would allow communities to act together to protect their
    privacy.

While these suggestions prevent trivial use of this API for user
tracking, they do not block it altogether. Within a single domain, a
site can continue to track the user during a session, and can then
pass all this information to the third party along with any
identifying information (names, credit card numbers, addresses)
obtained by the site. If a third party cooperates with multiple
sites to obtain such information, a profile can still be
created.

However, user tracking is to some extent possible even with no
cooperation from the user agent whatsoever, for instance by using
session identifiers in URLs, a technique already commonly used for
innocuous purposes but easily repurposed for user tracking (even
retroactively). This information can then be shared with other
sites, using visitors' IP addresses and other user-specific
data (e.g. user-agent headers and configuration settings) to combine
separate sessions into coherent user profiles.


## Cookie resurrection ## {#cookie-resurrection}

If the user interface for persistent storage presents data in the
persistent storage features described in this specification separately
from data in HTTP session cookies, then users are likely to delete
data in one and not the other. This would allow sites to use the two
features as redundant backup for each other, defeating a user's
attempts to protect his privacy.


## Sensitivity of data ## {#sensitivity-of-data}

User agents should treat persistently stored data as potentially
sensitive; it is quite possible for e-mails, calendar appointments,
health records, or other confidential documents to be stored in this
mechanism.

To this end, user agents should ensure that when deleting data,
it is promptly deleted from the underlying storage.


<!-- ============================================================ -->
# Security Considerations # {#security}
<!-- ============================================================ -->

## DNS spoofing attacks ## {#dns-spoofing-attacks}

Because of the potential for DNS spoofing attacks, one cannot
guarantee that a host claiming to be in a certain domain really is
from that domain. To mitigate this, pages can use TLS. Pages using TLS
can be sure that only pages using TLS that have certificates
identifying them as being from the same domain can access their
databases.


## Cross-directory attacks ## {#cross-directory-attacks}

Different authors sharing one host name, for example users hosting
content on `geocities.com`, all share one set of databases.

There is no feature to restrict the access by pathname. Authors on
shared hosts are therefore recommended to avoid using these features,
as it would be trivial for other authors to read the data and
overwrite it.

<aside class=note>
  Even if a path-restriction feature was made available, the usual DOM
  scripting security model would make it trivial to bypass this
  protection and access the data from any path.
</aside>

## Implementation risks ## {#implementation-risks}

The two primary risks when implementing these persistent storage
features are letting hostile sites read information from other
domains, and letting hostile sites write information that is then read
from other domains.

Letting third-party sites read data that is not supposed to be read
from their domain causes *information leakage*, For example, a
user's shopping wish list on one domain could be used by another
domain for targeted advertising; or a user's work-in-progress
confidential documents stored by a word-processing site could be
examined by the site of a competing company.

Letting third-party sites write data to the persistent storage of
other domains can result in *information spoofing*, which is
equally dangerous. For example, a hostile site could add records to a
user's wish list; or a hostile site could set a user's session
identifier to a known ID that the hostile site can then use to track
the user's actions on the victim site.

Thus, strictly following the <span>origin</span> model described in
this specification is important for user security.

If origins or database names are used to construct paths for
persistence to a file system they must be appropriately escaped to
prevent an adversary from accessing information from other origins
using relative paths such as "`../`".

## Persistence risks ## {#persistence-risks}

Practical implementations will persist data to a non-volatile storage
medium. Data will be serialized when stored and deserialized when
retrieved, although the details of the serialization format will be
user-agent specific. User agents are likely to change their
serialization format over time. For example, the format may be updated
to handle new data types, or to improve performance. To satisfy the
operational requirements of this specification, implementations must
therefore handle older serialization formats in some way. Improper
handling of older data can result in security issues. In addition to
basic serialization concerns, serialized data could encode assumptions
which are not valid in newer versions of the user agent.

A practical example of this is the [=RegExp=] type. The <a
abstract-op>StructuredSerializeForStorage</a> operation allows serializing [=RegExp=]
objects. A typical user agent will compile a regular expression into
native machine instructions, with assumptions about how the input data
is passed and results returned. If this internal state was serialized
as part of the data stored to the database, various problems could
arise when the internal representation was later deserialized. For
example, the means by which data was passed into the code could have
changed. Security bugs in the compiler output could have been
identified and fixed in updates to the user agent, but remain in the
serialized internal state.

User agents must identify and handle older data appropriately. One
approach is to include version identifiers in the serialization
format, and to reconstruct any internal state from script-visible
state when older data is encountered.

<!-- ============================================================ -->
# Revision History # {#revision-history}
<!-- ============================================================ -->

*This section is non-normative.*

The following is an informative summary of the changes since the last
publication of this specification. A complete revision history can be
found [here](https://github.com/w3c/IndexedDB/).
For the revision history of the first edition, see [that document's Revision History](https://www.w3.org/TR/2015/REC-IndexedDB-20150108/#revision-history).
For the revision history of the second edition, see [that document's Revision History](https://www.w3.org/TR/IndexedDB-2/#revision-history).

* The [=cleanup Indexed Database transactions=] algorithm now returns a value for integration with other specs. ([PR #232](https://github.com/w3c/IndexedDB/pull/232))
* Updated [partial interface definition](#global-scope) since {{WindowOrWorkerGlobalScope}} is now a `mixin` ([PR #238](https://github.com/w3c/IndexedDB/pull/238)).
* Added {{IDBFactory/databases()}} method. ([Issue #31](https://github.com/w3c/IndexedDB/issues/31))
* Added {{IDBTransaction/commit()}} method. ([Issue #234](https://github.com/w3c/IndexedDB/issues/234))
* Added {{IDBCursor/request}} attribute. ([Issue #255](https://github.com/w3c/IndexedDB/issues/255))
* Removed handling for nonstandard `lastModifiedDate` property of {{File}} objects. ([Issue #215](https://github.com/w3c/IndexedDB/issues/215))
* Remove escaping {{IDBKeyRange/includes()}} method. ([Issue #294](https://github.com/w3c/IndexedDB/issues/294))
* Restrict array keys to [=/Array exotic objects=] (i.e. disallow proxies). ([Issue #309](https://github.com/w3c/IndexedDB/issues/309])
* Transactions are now temporarily made inactive during clone operations.

<!-- ============================================================ -->
# Acknowledgements # {#acknowledgements}
<!-- ============================================================ -->

*This section is non-normative.*

Special thanks to Nikunj Mehta, the original author of the first
edition, and Jonas Sicking, Eliot Graff, Andrei Popescu, and Jeremy
Orlow, additional editors of the first edition.

Garret Swart was extremely influential in the design of this specification.

Thanks to Tab Atkins, Jr. for creating and maintaining
[Bikeshed](https://github.com/tabatkins/bikeshed), the
specification authoring tool used to create this document, and
for his general authoring advice.

Special thanks to
Chris Anderson,
Jake Archibald,
Yannic Bonenberger,
Andreas Butler,
Pablo Castro,
Victor Costan,
Kristof Degrave,
Domenic Denicola,
Jake Drew,
Ben Dilts,
Jo&atilde;o Eiras,
Alec Flett,
Dana Florescu,
David Grogan,
Israel Hilerio,
Jerome Hode,
Kyle Huey,
Philip Jägenstedt,
Laxminarayan G Kamath A,
Anne van Kesteren,
Adam Klein,
Marijn Kruisselbrink,
Tobie Langel,
Kang-Hao Lu,
Andrea Marchesini,
Josh Matthews,
Glenn Maynard,
Isiah Meadows,
Ms2ger,
Odin Omdal,
Danillo Paiva,
Olli Pettay,
Addison Phillips,
Simon Pieters,
Anthony Ramine,
Yonathan Randolph,
Arun Ranganathan,
Kagami Sascha Rosylight,
Margo Seltzer,
Maciej Stachowiak,
Andrew Sutherland,
Yaron Tausky,
Bevis Tseng,
Ben Turner,
Kyaw Tun,
Hans Wennborg,
Shawn Wilsher,
Brett Zamir,
Boris Zbarsky,
Zhiqiang Zhang,
and
Kris Zyp,
all of whose feedback and suggestions have led to improvements to this
specification.
